新书推介:《语义网技术体系》
作者:瞿裕忠,胡伟,程龚
   XML论坛     W3CHINA.ORG讨论区     >>计算机科学论坛<<     SOAChina论坛     Blog     开放翻译计划     新浪微博  
 
  • 首页
  • 登录
  • 注册
  • 软件下载
  • 资料下载
  • 核心成员
  • 帮助
  •   Add to Google

    >> 本版讨论高级C/C++编程、代码重构(Refactoring)、极限编程(XP)、泛型编程等话题
    [返回] 计算机科学论坛计算机技术与应用『 C/C++编程思想 』 → 网格模型高级技术(4) 查看新帖用户列表

      发表一个新主题  发表一个新投票  回复主题  (订阅本版) 您是本帖的第 16447 个阅读者浏览上一篇主题  刷新本主题   树形显示贴子 浏览下一篇主题
     * 贴子主题: 网格模型高级技术(4) 举报  打印  推荐  IE收藏夹 
       本主题类别:     
     卷积内核 帅哥哟,离线,有人找我吗?
      
      
      威望:8
      头衔:总统
      等级:博士二年级(版主)
      文章:3942
      积分:27590
      门派:XML.ORG.CN
      注册:2004/7/21

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给卷积内核发送一个短消息 把卷积内核加入好友 查看卷积内核的个人资料 搜索卷积内核在『 C/C++编程思想 』的所有贴子 访问卷积内核的主页 引用回复这个贴子 回复这个贴子 查看卷积内核的博客楼主
    发贴心情 网格模型高级技术(4)

    索引顶点混合

    Direct3D通过索引顶点混合,扩展了使用多个混合矩阵对顶点进行混合的支持。在索引顶点混合中,混合矩阵被保存在矩阵调色板(可以看成一个矩阵数组)中,使用矩阵索引来引用特定的混合矩阵。矩阵索引使用8位无符号整数表示,由每个顶点提供,因为Direct3D中限定每个顶点最多受到4个混合矩阵的影响,所以每个顶点最多具有4个矩阵索引,每个顶点的矩阵索引被组合成一个DWORD类型的整数存储和表示。因为每个顶点最多受4个混合矩阵的影响,所以在渲染一个三角形时最多可能需要使用12个混合矩阵,在这种情况下,矩阵调色板中最少需要包含12个混合矩阵。

    下图演示了一个顶点使用矩阵索引引用4个混合矩阵,图中的顶点通过矩阵索引引用矩阵调色板中索引为0、2、5、6的混合矩阵:

    按此在新窗口浏览图片

    下图演示了渲染一个三角形时,如何通过矩阵索引引用矩阵调色板中的12个混合矩阵:

    按此在新窗口浏览图片

    在渲染图形时,要想启用索引顶点混合,需要将渲染状态D3DRS_INDEXEDVERTEXBLENDENABLE设置为TRUE,如果启用了索引顶点混合,则在顶点数据中就需要包含矩阵索引数据。如果将渲染状态D3DRS_INDEXEDVERTEXBLENDENABLE设置为FALSE则禁用索引顶点混合,但是又启用了图形混合功能,这时在顶点数据中就不需要包含矩阵索引数据,每个顶点的矩阵索引默认为0~3。

    D3DRS_INDEXEDVERTEXBLENDENABLE
    bool value that enables or disables indexed vertex blending. The default value is FALSE. When set to TRUE, indexed vertex blending is enabled. When set to FALSE, indexed vertex blending is disabled. If this render state is enabled, the user must pass matrix indices as a packed DWORDwith every vertex. When the render state is disabled and vertex blending is enabled through the D3DRS_VERTEXBLEND state, it is equivalent to having matrix indices 0, 1, 2, 3 in every vertex.
    D3DCAPS结构体的成员变量MaxVertexBlendMatrixIndex表示当前设备对索引顶点混合的支持,如果MaxVertexBlendMatrixIndex的值为0,表示当前硬件设备不支持索引顶点混合。如果MaxVertexBlendMatrixIndex的值不为0,表示混合矩阵的最大索引为MaxVertexBlendMatrixIndex,也就是当前硬件设备支持的矩阵调色板最大容量为MaxVertexBlendMatrixIndex+1,表示矩阵调色板最大可以容纳MaxVertexBlendMatrixIndex+1个混合矩阵。如果顶点中包含法线信息,则也需要对法线数据进行混合,这时矩阵调色板中矩阵的最大数量为(MaxVertexBlendMatrixIndex+1)/ 2。如果使用软件顶点处理模式,则矩阵调色板的最大容量为256,不管是否需要对法线向量进行混合。

    MaxVertexBlendMatrixIndex
    DWORD value that specifies the maximum matrix index that can be indexed into using the per-vertex indices. The number of matrices is MaxVertexBlendMatrixIndex + 1, which is the size of the matrix palette. If normals are present in the vertex data that needs to be blended for lighting, then the number of matrices is half the number specified by this capability flag. If MaxVertexBlendMatrixIndex is set to zero, the driver does not support indexed vertex blending. If this value is not zero then the valid range of indices is zero through MaxVertexBlendMatrixIndex.
    A zero value for MaxVertexBlendMatrixIndex indicates that the driver does not support indexed matrices.

    When software vertex processing is used, 256 matrices could be used for indexed vertex blending, with or without normal blending.

    For a given physical device, this capability may vary across Direct3D devices depending on the parameters supplied to IDirect3D9::CreateDevice.

    综合上面图形混合和索引顶点混合的内容,对顶点混合可以总结如下:

    (1)不管是否使用索引顶点混合,混合矩阵都是通过索引从矩阵调色板中引用。

    (2)如果不使用索引顶点混合,则混合矩阵索引最大为3,而且在顶点数据中不需要包含矩阵索引,矩阵索引默认为0~3。

    (3)如果使用索引顶点混合,矩阵索引最大为255,而且在顶点数据中需要指定影响该顶点混合矩阵的索引。

    (4)使用图形混合之前,首先需要检查当前设备支持的调色板容量是否满足要求,因为使用软件顶点处理模式时,最大混合矩阵索引为255,肯定能满足要求,所以如果硬件顶点处理模式下矩阵调色板容量不能满足要求,只需简单转换为使用软件顶点处理模式即可。

    蒙皮骨骼动画跟单纯的骨骼动画相比,只是使用了顶点混合技术,解决单纯的骨骼动画存在的问题。

    首先我们需要定义包含顶点混合权重和法线向量的结构体,还需要定义两个混合矩阵:

    struct sBlendVertex{ D3DXVECTOR3 pos; float  blend; D3DXVECTOR3 normal;};
    #define BLEND_VERTEX_FVF (D3DFVF_XYZB1 | D3DFVF_NORMAL)
    CDXUTMesh* g_dxut_mesh;D3DXMATRIX g_blend_matrix_1;D3DXMATRIX g_blend_matrix_2;
    因为顶点所有骨骼权重之和是1,所以如果1个顶点受到n块骨骼的影响,那么为顶点指定n-1个权重即可,最后一个权重可以通过1减去n-1个权重之和得到。这里每个顶点只受两个骨骼矩阵的影响,所以在上面的顶点结构中只需提供一个顶点权重即可。

    接着在回调函数ModifyDeviceSetttings()中用下列语句检查硬件是否支持索引顶点混合,如果当前硬件不支持索引顶点混合,则使用软件顶点处理模式:

    if(pDeviceSettings->BehaviorFlags & D3DCREATE_HARDWARE_VERTEXPROCESSING) pDeviceSettings->BehaviorFlags = D3DCREATE_MIXED_VERTEXPROCESSING;
    // if current device does not support vertex blending, use software device.if(pCaps->MaxVertexBlendMatrices < 1) pDeviceSettings->BehaviorFlags = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
    接下来在回调函数OnCreateDevice()中从.x文件中加载网格模型,因为该网格模型中并没有包含骨骼权重信息,所以首先调用CDXUTMesh:SetFVF()设置网格模型的顶点灵活格式,然后为该网格模型的每个顶点添加权重:

    g_dxut_mesh = new CDXUTMesh();V_RETURN(g_dxut_mesh->Create(pd3dDevice, L"mslogo.x"));
    // add vertex blending weight and normal informationg_dxut_mesh->SetFVF(pd3dDevice, BLEND_VERTEX_FVF);
    DWORD num_vertices = g_dxut_mesh->GetMesh()->GetNumVertices();
    IDirect3DVertexBuffer9* vertex_buffer;g_dxut_mesh->GetMesh()->GetVertexBuffer(&vertex_buffer);
    sBlendVertex* blend_vertices;vertex_buffer->Lock(0, 0, (void**)&blend_vertices, 0);
    // count min and max x coordinate of all vertices for calculating vertex blending weight
    float min_x =  1e10f;float max_x = -1e10f;
    for(DWORD i = 0; i < num_vertices; i++){ if(blend_vertices[i].pos.x < min_x)  min_x = blend_vertices[i].pos.x;
     if(blend_vertices[i].pos.x > max_x)  max_x = blend_vertices[i].pos.x;}
    // calculate for all vertices blending weightfor(DWORD i = 0; i < num_vertices; i++){ float scale = (blend_vertices[i].pos.x - min_x) / (max_x - min_x); blend_vertices[i].blend = 1.0f - sinf(scale * D3DX_PI);}
    vertex_buffer->Unlock();vertex_buffer->Release(); 
    接下来在回调函数中OnFrameMove()中实时构造并设置骨骼变换矩阵:

    float scale = (float) fTime;
    // calculate blend matrixD3DXVECTOR3 axis(2 + sinf(scale * 3.1f), 2 + sinf(scale * 3.3f), sinf(scale * 3.5f));D3DXMatrixIdentity(&g_blend_matrix_1);D3DXMatrixRotationAxis(&g_blend_matrix_2, &axis, sinf(3 * scale));
    // set vertex blend method and blend matrixpd3dDevice->SetRenderState(D3DRS_VERTEXBLEND, D3DVBF_1WEIGHTS);pd3dDevice->SetTransform(D3DTS_WORLDMATRIX(0), &g_blend_matrix_1);pd3dDevice->SetTransform(D3DTS_WORLDMATRIX(1), &g_blend_matrix_2);
    上面代码中的最后三行是相互对应的,缺一不可。首先将渲染状态D3DRS_VERTEXBLEND设置为D3DVBF_1WEIGHTS,渲染状态D3DRS_VERTEXBLEND用来指定进行顶点混合时所使用的矩阵的数目,这里将它设置为D3DVBF_1WEIGHTS,表示用宏D3DTS_WORLDMATRIX(index)设置两个骨骼矩阵进行顶点混合,而且这两个骨骼矩阵的索引号分别是0和1。

    因为要进行顶点混合,所以函数SetTransform()将要设置的不再是普通的世界坐标变换矩阵,而是骨骼变换矩阵,所以它的第一个参数应该采用宏D3DTS_WORLDMATRIX(index)的格式,而不像以前一样使用标识符D3DTS_WORLD。宏D3DTS_WORLDMATRIX(index)的定义如下:

    #define D3DTS_WORLDMATRIX(index) (D3DTRANSFORMSTATETYPE)(index + 256)

    该宏负责将索引号index映射到相应的变换状态下。

    在设置好各个骨骼矩阵之后,在回调函数OnFrameRender()中渲染网格模型:

    g_dxut_mesh->Render(pd3dDevice);

    运行截图:

    按此在新窗口浏览图片


       收藏   分享  
    顶(0)
      




    ----------------------------------------------
    事业是国家的,荣誉是单位的,成绩是领导的,工资是老婆的,财产是孩子的,错误是自己的。

    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2009/1/5 13:42:00
     
     卷积内核 帅哥哟,离线,有人找我吗?
      
      
      威望:8
      头衔:总统
      等级:博士二年级(版主)
      文章:3942
      积分:27590
      门派:XML.ORG.CN
      注册:2004/7/21

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给卷积内核发送一个短消息 把卷积内核加入好友 查看卷积内核的个人资料 搜索卷积内核在『 C/C++编程思想 』的所有贴子 访问卷积内核的主页 引用回复这个贴子 回复这个贴子 查看卷积内核的博客2
    发贴心情 
    主程序:


    #include "dxstdafx.h"
    #include "resource.h"

    #pragma warning(disable : 4127 4995)

    struct sBlendVertex
    {
        D3DXVECTOR3 pos;
        float        blend;
        D3DXVECTOR3 normal;
    };

    #define BLEND_VERTEX_FVF (D3DFVF_XYZB1 | D3DFVF_NORMAL)

    #define IDC_TOGGLE_FULLSCREEN    1
    #define IDC_TOGGLE_REF            2
    #define IDC_CHANGE_DEVICE        3

    #define release_com(p)    do { if(p) { (p)->Release(); (p) = NULL; } } while(0)

    ID3DXFont*                    g_font;
    ID3DXSprite*                g_text_sprite;
    bool                        g_show_help;

    CDXUTDialogResourceManager    g_dlg_resource_manager;
    CD3DSettingsDlg                g_settings_dlg;
    CDXUTDialog                    g_button_dlg;

    CDXUTMesh*                    g_dxut_mesh;
    D3DXMATRIX                    g_blend_matrix_1;
    D3DXMATRIX                    g_blend_matrix_2;

    //--------------------------------------------------------------------------------------
    // Rejects any devices that aren't acceptable by returning false
    //--------------------------------------------------------------------------------------
    bool CALLBACK IsDeviceAcceptable( D3DCAPS9* pCaps, D3DFORMAT AdapterFormat,
                                      D3DFORMAT BackBufferFormat, bool bWindowed, void* pUserContext )
    {
        // Typically want to skip backbuffer formats that don't support alpha blending

        IDirect3D9* pD3D = DXUTGetD3DObject();

        if( FAILED( pD3D->CheckDeviceFormat( pCaps->AdapterOrdinal, pCaps->DeviceType, AdapterFormat,
                        D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING, D3DRTYPE_TEXTURE, BackBufferFormat ) ) )
            return false;

        return true;
    }


    //--------------------------------------------------------------------------------------
    // Before a device is created, modify the device settings as needed.
    //--------------------------------------------------------------------------------------
    bool CALLBACK ModifyDeviceSettings( DXUTDeviceSettings* pDeviceSettings, const D3DCAPS9* pCaps, void* pUserContext )
    {
        // If video card does not support hardware vertex processing, then uses sofaware vertex processing.
        if((pCaps->DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) == 0)
            pDeviceSettings->BehaviorFlags = D3DCREATE_SOFTWARE_VERTEXPROCESSING;

        static bool is_first_time = true;

        if(is_first_time)
        {
            is_first_time = false;

            // if using reference device, then pop a warning message box.
            if(pDeviceSettings->DeviceType == D3DDEVTYPE_REF)
                DXUTDisplaySwitchingToREFWarning();
        }

        if(pDeviceSettings->BehaviorFlags & D3DCREATE_HARDWARE_VERTEXPROCESSING)
            pDeviceSettings->BehaviorFlags = D3DCREATE_MIXED_VERTEXPROCESSING;

        // if current device does not support vertex blending, use software device.
        if(pCaps->MaxVertexBlendMatrices < 1)
            pDeviceSettings->BehaviorFlags = D3DCREATE_SOFTWARE_VERTEXPROCESSING;

        return true;
    }

    //--------------------------------------------------------------------------------------
    // Remove path from fullname, and convert filename from multibyte to wchar.
    //--------------------------------------------------------------------------------------
    void RemovePathFromFileName(LPSTR fullname, LPWSTR wfilename)
    {
        WCHAR wbuf[MAX_PATH]  = {0};
        MultiByteToWideChar(CP_ACP, 0, fullname, -1, wbuf, MAX_PATH);

        LPWSTR w_last_back_slash = wcsrchr(wbuf, '\\');

        if(w_last_back_slash)
            lstrcpy(wfilename, ++w_last_back_slash);
        else
            lstrcpy(wfilename, wbuf);
    }


    //--------------------------------------------------------------------------------------
    // Create any D3DPOOL_MANAGED resources here
    //--------------------------------------------------------------------------------------
    HRESULT CALLBACK OnCreateDevice( IDirect3DDevice9* pd3dDevice,
                                     const D3DSURFACE_DESC* pBackBufferSurfaceDesc,
                                     void* pUserContext )
    {
        HRESULT    hr;

        V_RETURN(g_dlg_resource_manager.OnCreateDevice(pd3dDevice));
        V_RETURN(g_settings_dlg.OnCreateDevice(pd3dDevice));

        D3DXCreateFont(pd3dDevice, 18, 0, FW_BOLD, 1, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY,
                       DEFAULT_PITCH | FF_DONTCARE, L"Arial", &g_font);
        
        g_dxut_mesh = new CDXUTMesh();
        V_RETURN(g_dxut_mesh->Create(pd3dDevice, L"mslogo.x"));

        // add vertex blending weight and normal information
        g_dxut_mesh->SetFVF(pd3dDevice, BLEND_VERTEX_FVF);
        
        IDirect3DVertexBuffer9* vertex_buffer;
        g_dxut_mesh->GetMesh()->GetVertexBuffer(&vertex_buffer);

        sBlendVertex* blend_vertices;
        vertex_buffer->Lock(0, 0, (void**)&blend_vertices, 0);

        // count min and max x coordinate of all vertices for calculating vertex blending weight

        DWORD num_vertices = g_dxut_mesh->GetMesh()->GetNumVertices();

        float min_x =  1e10f;
        float max_x = -1e10f;    

        for(DWORD i = 0; i < num_vertices; i++)
        {
            if(blend_vertices[i].pos.x < min_x)
                min_x = blend_vertices[i].pos.x;

            if(blend_vertices[i].pos.x > max_x)
                max_x = blend_vertices[i].pos.x;
        }

        // calculate for all vertices blending weight
        for(DWORD i = 0; i < num_vertices; i++)
        {
            float scale = (blend_vertices[i].pos.x - min_x) / (max_x - min_x);
            blend_vertices[i].blend = 1.0f - sinf(scale * D3DX_PI);
        }

        vertex_buffer->Unlock();
        vertex_buffer->Release();        

        return S_OK;
    }


    //--------------------------------------------------------------------------------------
    // Create any D3DPOOL_DEFAULT resources here
    //--------------------------------------------------------------------------------------
    HRESULT CALLBACK OnResetDevice( IDirect3DDevice9* pd3dDevice,
                                    const D3DSURFACE_DESC* pBackBufferSurfaceDesc,
                                    void* pUserContext )
    {
        HRESULT hr;

        V_RETURN(g_dlg_resource_manager.OnResetDevice());
        V_RETURN(g_settings_dlg.OnResetDevice());
        V_RETURN(g_font->OnResetDevice());
        V_RETURN(D3DXCreateSprite(pd3dDevice, &g_text_sprite));

        // set dialog position and size

        g_button_dlg.SetLocation(pBackBufferSurfaceDesc->Width - 170, 0);
        g_button_dlg.SetSize(170, 170);    

        // setup view matrix

        D3DXMATRIX mat_view;
        D3DXVECTOR3 eye(0.0f, 0.0f,  -10.0f);
        D3DXVECTOR3  at(0.0f, 0.0f,    0.0f);
        D3DXVECTOR3  up(0.0f, 1.0f,    0.0f);

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

        // set projection matrix
        D3DXMATRIX mat_proj;
        float aspect = (float)pBackBufferSurfaceDesc->Width / pBackBufferSurfaceDesc->Height;
        D3DXMatrixPerspectiveFovLH(&mat_proj, D3DX_PI/4, aspect, 1.0f, 100.0f);
        pd3dDevice->SetTransform(D3DTS_PROJECTION, &mat_proj);    

        // set material
        D3DMATERIAL9 material;
        ZeroMemory(&material, sizeof(D3DMATERIAL9));

        material.Ambient.r = material.Diffuse.r = 1.0f;
        material.Ambient.g = material.Diffuse.g = 1.0f;
        material.Ambient.b = material.Diffuse.b = 1.0f;
        material.Ambient.a = material.Diffuse.a = 1.0f;

        pd3dDevice->SetMaterial(&material);

        // setup light
        
        D3DLIGHT9 light;
        ZeroMemory(&light, sizeof(D3DLIGHT9));

        light.Type       = D3DLIGHT_DIRECTIONAL;
        light.Diffuse.r  = 1.5f;
        light.Diffuse.g  = 0.8f;
        light.Diffuse.b  = 1.0f;    

        D3DXVECTOR3 light_dir(0.0f, 0.0f, 10.0f);    
        D3DXVec3Normalize((D3DXVECTOR3*) &light.Direction, &light_dir);
        pd3dDevice->SetLight(0, &light);
        pd3dDevice->LightEnable(0, TRUE);
        pd3dDevice->SetRenderState(D3DRS_LIGHTING, TRUE);

        pd3dDevice->SetRenderState(D3DRS_AMBIENT, 0x00404040);

        return S_OK;
    }

    //--------------------------------------------------------------------------------------
    // Release resources created in the OnResetDevice callback here
    //--------------------------------------------------------------------------------------
    void CALLBACK OnLostDevice( void* pUserContext )
    {
        g_dlg_resource_manager.OnLostDevice();
        g_settings_dlg.OnLostDevice();
        g_font->OnLostDevice();

        release_com(g_text_sprite);
    }


    //--------------------------------------------------------------------------------------
    // Release resources created in the OnCreateDevice callback here
    //--------------------------------------------------------------------------------------
    void CALLBACK OnDestroyDevice( void* pUserContext )
    {
        g_dlg_resource_manager.OnDestroyDevice();
        g_settings_dlg.OnDestroyDevice();    

        release_com(g_font);
        SAFE_DELETE(g_dxut_mesh);
    }

    //--------------------------------------------------------------------------------------
    // Handle updates to the scene
    //--------------------------------------------------------------------------------------
    void CALLBACK OnFrameMove( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime, void* pUserContext )
    {    
        float scale = (float) fTime;

        // calculate blend matrix
        D3DXVECTOR3 axis(2 + sinf(scale * 3.1f), 2 + sinf(scale * 3.3f), sinf(scale * 3.5f));
        D3DXMatrixIdentity(&g_blend_matrix_1);
        D3DXMatrixRotationAxis(&g_blend_matrix_2, &axis, sinf(3 * scale));

        // set vertex blend method and blend matrix
        pd3dDevice->SetRenderState(D3DRS_VERTEXBLEND, D3DVBF_1WEIGHTS);
        pd3dDevice->SetTransform(D3DTS_WORLDMATRIX(0), &g_blend_matrix_1);
        pd3dDevice->SetTransform(D3DTS_WORLDMATRIX(1), &g_blend_matrix_2);
    }

    //--------------------------------------------------------------------------------------
    // Render the helper information
    //--------------------------------------------------------------------------------------
    void RenderText()
    {
        CDXUTTextHelper text_helper(g_font, g_text_sprite, 20);
        
        text_helper.Begin();

        // show frame and device states
        text_helper.SetInsertionPos(5, 5);
        text_helper.SetForegroundColor( D3DXCOLOR(1.0f, 0.475f, 0.0f, 1.0f) );
        text_helper.DrawTextLine( DXUTGetFrameStats(true) );
        text_helper.DrawTextLine( DXUTGetDeviceStats() );

        // show helper information
        
        const D3DSURFACE_DESC* surface_desc = DXUTGetBackBufferSurfaceDesc();

        if(g_show_help)
        {
            text_helper.SetInsertionPos(10, surface_desc->Height - 15 * 6);
            text_helper.SetForegroundColor( D3DXCOLOR(1.0f, 0.475f, 0.0f, 1.0f) );
            text_helper.DrawTextLine(L"Controls (F1 to hide):");
            
            text_helper.SetInsertionPos(40, surface_desc->Height - 15 * 4);
            text_helper.DrawTextLine(L"Quit: ESC");
        }
        else
        {
            text_helper.SetInsertionPos(10, surface_desc->Height - 15 * 4);
            text_helper.SetForegroundColor( D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f) );
            text_helper.DrawTextLine(L"Press F1 for help");
        }

        text_helper.End();
    }

    //--------------------------------------------------------------------------------------
    // Render the scene
    //--------------------------------------------------------------------------------------
    void CALLBACK OnFrameRender( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime, void* pUserContext )
    {
        HRESULT hr;

        if(g_settings_dlg.IsActive())
        {
            g_settings_dlg.OnRender(fElapsedTime);
            return;
        }

        // Clear the render target and the zbuffer
        V( pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_ARGB(0, 0, 0, 0), 1.0f, 0) );

        // Render the scene
        if( SUCCEEDED( pd3dDevice->BeginScene() ) )
        {                    
            g_dxut_mesh->Render(pd3dDevice);
            RenderText();
            V(g_button_dlg.OnRender(fElapsedTime));

            V( pd3dDevice->EndScene() );
        }
    }


    //--------------------------------------------------------------------------------------
    // Handle messages to the application
    //--------------------------------------------------------------------------------------
    LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam,
                              bool* pbNoFurtherProcessing, void* pUserContext )
    {
        *pbNoFurtherProcessing = g_dlg_resource_manager.MsgProc(hWnd, uMsg, wParam, lParam);
        if(*pbNoFurtherProcessing)
            return 0;

        if(g_settings_dlg.IsActive())
        {
            g_settings_dlg.MsgProc(hWnd, uMsg, wParam, lParam);
            return 0;
        }

        *pbNoFurtherProcessing = g_button_dlg.MsgProc(hWnd, uMsg, wParam, lParam);
        if(*pbNoFurtherProcessing)
            return 0;

        return 0;
    }


    //--------------------------------------------------------------------------------------
    // Handle keybaord event
    //--------------------------------------------------------------------------------------
    void CALLBACK OnKeyboardProc(UINT charater, bool is_key_down, bool is_alt_down, void* user_context)
    {
        if(is_key_down)
        {
            switch(charater)
            {
            case VK_F1:
                g_show_help = !g_show_help;
                break;
            }
        }
    }

    //--------------------------------------------------------------------------------------
    // Handle events for controls
    //--------------------------------------------------------------------------------------
    void CALLBACK OnGUIEvent(UINT event, int control_id, CDXUTControl* control, void* user_context)
    {
        switch(control_id)
        {
        case IDC_TOGGLE_FULLSCREEN:
            DXUTToggleFullScreen();
            break;

        case IDC_TOGGLE_REF:
            DXUTToggleREF();
            break;

        case IDC_CHANGE_DEVICE:
            g_settings_dlg.SetActive(true);
            break;
        }
    }

    //--------------------------------------------------------------------------------------
    // Initialize dialogs
    //--------------------------------------------------------------------------------------
    void InitDialogs()
    {
        g_settings_dlg.Init(&g_dlg_resource_manager);
        g_button_dlg.Init(&g_dlg_resource_manager);

        g_button_dlg.SetCallback(OnGUIEvent);

        int x = 35, y = 10, width = 125, height = 22;

        g_button_dlg.AddButton(IDC_TOGGLE_FULLSCREEN, L"Toggle full screen", x, y,         width, height);
        g_button_dlg.AddButton(IDC_TOGGLE_REF,          L"Toggle REF (F3)",     x, y += 24, width, height);
        g_button_dlg.AddButton(IDC_CHANGE_DEVICE,      L"Change device (F2)", x, y += 24, width, height, VK_F2);    
    }

    //--------------------------------------------------------------------------------------
    // Initialize everything and go into a render loop
    //--------------------------------------------------------------------------------------
    INT WINAPI WinMain( HINSTANCE, HINSTANCE, LPSTR, int )
    {
        // Enable run-time memory check for debug builds.
    #if defined(DEBUG) | defined(_DEBUG)
        _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
    #endif

        // Set the callback functions
        DXUTSetCallbackDeviceCreated( OnCreateDevice );
        DXUTSetCallbackDeviceReset( OnResetDevice );
        DXUTSetCallbackDeviceLost( OnLostDevice );
        DXUTSetCallbackDeviceDestroyed( OnDestroyDevice );
        DXUTSetCallbackMsgProc( MsgProc );
        DXUTSetCallbackFrameRender( OnFrameRender );
        DXUTSetCallbackFrameMove( OnFrameMove );
        DXUTSetCallbackKeyboard(OnKeyboardProc);
       
        // TODO: Perform any application-level initialization here
        InitDialogs();

        // Initialize DXUT and create the desired Win32 window and Direct3D device for the application
        DXUTInit( true, true, true ); // Parse the command line, handle the default hotkeys, and show msgboxes
        DXUTSetCursorSettings( true, true ); // Show the cursor and clip it when in full screen
        DXUTCreateWindow( L"Vertex Blend" );
        DXUTCreateDevice( D3DADAPTER_DEFAULT, true, 640, 480, IsDeviceAcceptable, ModifyDeviceSettings );

        // Start the render loop
        DXUTMainLoop();

        // TODO: Perform any application-level cleanup here

        return DXUTGetExitCode();
    }

    [B][URL=http://www.cppblog.com/Files/changingnow/VertexBlend.rar]下载示例工程[/URL][/B]

    ----------------------------------------------
    事业是国家的,荣誉是单位的,成绩是领导的,工资是老婆的,财产是孩子的,错误是自己的。

    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2009/1/5 13:43:00
     
     卷积内核 帅哥哟,离线,有人找我吗?
      
      
      威望:8
      头衔:总统
      等级:博士二年级(版主)
      文章:3942
      积分:27590
      门派:XML.ORG.CN
      注册:2004/7/21

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给卷积内核发送一个短消息 把卷积内核加入好友 查看卷积内核的个人资料 搜索卷积内核在『 C/C++编程思想 』的所有贴子 访问卷积内核的主页 引用回复这个贴子 回复这个贴子 查看卷积内核的博客3
    发贴心情 
    蒙皮骨骼动画网格模型接口是对上一节骨骼动画网格模型接口的扩展,添加了处理蒙皮信息的功能。

    进一步扩展结构体D3DXMESHCONTAINER

    为了在网格模型中包含蒙皮信息,需要进一步扩展D3DXMESHCONTAINER_DERIVEED,其定义如下:

    struct D3DXMESHCONTAINER_DERIVED : public D3DXMESHCONTAINER{ IDirect3DTexture9**  ppTextures; ID3DXMesh*  pOrgMesh; DWORD   MaxBonesInflPerVertex; DWORD   NumAttrGroups; ID3DXBuffer*  pBoneCombBuffer; D3DXMATRIX**  ppBoneMatrices; D3DXMATRIX**  ppBoneOffsetMatrices; DWORD   NumMatrixPalettes; bool   UseSoftwareVP;};
    当加载原网格模型并由此生成一个蒙皮网格时,会用D3DXMESHCONTAINER::MeshData::pMesh存储所生成的蒙皮网格模型,这时需要将初始网格模型保存下来,这就是pOrgMesh的作用。变量MaxBonesInflPerVertex表示每个顶点最多受多少骨骼的影响,指针变量pBoneCombBuffer指向骨骼结合表,骨骼结合表中的数据按属性组结构体D3DXBONECOMBINATION组织起来,该结构体定义如下:

    Describes a subset of the mesh that has the same attribute and bone combination.

    typedef struct D3DXBONECOMBINATION {    DWORD AttribId;    DWORD FaceStart;    DWORD FaceCount;    DWORD VertexStart;    DWORD VertexCount;    DWORD * BoneId;} D3DXBONECOMBINATION, *LPD3DXBONECOMBINATION;
    Members
    AttribId
    Attribute table identifier.
    FaceStart
    Starting face.
    FaceCount
    Face count.
    VertexStart
    Starting vertex.
    VertexCount
    Vertex count.
    BoneId
    Pointer to an array of values that identify each of the bones that can be drawn in a single drawing call. Note that the array can be of variable length to accommodate variable length bone combinations of ID3DXSkinInfo::ConvertToIndexedBlendedMesh.

    The size of the array varies based on the type of mesh generated. A non-indexed mesh array size is equal to the number of weights per vertex (pMaxVertexInfl in ID3DXSkinInfo::ConvertToBlendedMesh). An indexed mesh array size is equal to the number of bone matrix palette entries (paletteSize in ID3DXSkinInfo::ConvertToIndexedBlendedMesh).
    Remarks
    The subset of the mesh described by D3DXBONECOMBINATION can be rendered in a single drawing call.

    结构体D3DXBONECOMBINATION用来描述网格中具有同样属性的部分,也就是网格模型的一个子集,这个网格模型子集也称为属性组。属性组实际上是用来标识网格模型中被指定的骨骼矩阵所影响的子网格,不同属性组所标识的子网格需要用不同的纹理、材质进行渲染,该子网格可以通过调用函数DrawIndexedPrimitive()或者DrawSubset()进行绘制。

    成员变量BoneId指向一个数组,该数组表示的是在单独的一次绘制中,即一次DrawSubset()函数调用中所用到的全部骨骼矩阵,该数组的大小与将要生成的蒙皮网格类型有关,在索引顶点混合蒙皮网格中,它的大小等于函数ConvertToIndexedBlendedMesh()中的输入参数paletteSize,也就是结构体D3DXMESHCONTAINER_DERIVEED的成员变量NumMatrixPalettes。变量NumMatrixPalettes表示进行索引顶点混合时所需要的矩阵调色板的容量,它的数值需要根据硬件设备能力进行相应的设置。

    cAllocateHierarchy类的设计实现

    蒙皮骨骼动画网格模型接口中cAllocateHierarchy类和骨骼动画网格模型接口中的cAllocateHierarchy类基本相同,区别较大的是CreateMeshContainer()函数中增加了对蒙皮信息的处理:

    // generate skin meshif(skin_info != NULL){ new_mesh_container->pSkinInfo = skin_info; skin_info->AddRef();
     new_mesh_container->pOrgMesh = mesh_ptr; mesh_ptr->AddRef();
     UINT num_bones = skin_info->GetNumBones(); new_mesh_container->ppBoneOffsetMatrices = new D3DXMATRIX*[num_bones];
     if(new_mesh_container->ppBoneOffsetMatrices == NULL) {  DestroyMeshContainer(new_mesh_container);  return E_OUTOFMEMORY; }
     for(UINT i = 0; i < num_bones; i++)  new_mesh_container->ppBoneOffsetMatrices[i] = new_mesh_container->pSkinInfo->GetBoneOffsetMatrix(i);
     hr = GenerateSkinnedMesh(new_mesh_container);
     if(FAILED(hr)) {  DestroyMeshContainer(new_mesh_container);  return hr; }}
    CreateMeshContainer()函数中处理蒙皮信息的关键是调用自定义函数GenerateSkinnedMesh()来生成蒙皮网格模型,其定义如下:


    HRESULT cAllocateHierarchy::GenerateSkinnedMesh(D3DXMESHCONTAINER_DERIVED* mesh_container)
    {
        ID3DXSkinInfo* skin_info = mesh_container->pSkinInfo;

        if(skin_info == NULL)
            return S_OK;

        release_com(mesh_container->MeshData.pMesh);
        release_com(mesh_container->pBoneCombBuffer);

        HRESULT hr;
        IDirect3DIndexBuffer9* index_buffer;
        
        if(FAILED(hr = mesh_container->pOrgMesh->GetIndexBuffer(&index_buffer)))
            return hr;

        DWORD max_faces_infl_per_triangle;
        hr = skin_info->GetMaxFaceInfluences(index_buffer, mesh_container->pOrgMesh->GetNumFaces(),
                                             &max_faces_infl_per_triangle);

        index_buffer->Release();

        if(FAILED(hr))
            return hr;

        max_faces_infl_per_triangle = min(max_faces_infl_per_triangle, 12);

        IDirect3DDevice9* device = DXUTGetD3DDevice();

        D3DCAPS9 caps;
        device->GetDeviceCaps(&caps);

        if((caps.MaxVertexBlendMatrixIndex+1)/2 < max_faces_infl_per_triangle)
        {
            // use software vertex processing
            mesh_container->NumMatrixPalettes = min(256, skin_info->GetNumBones());
            mesh_container->UseSoftwareVP = true;
        }
        else
        {
            // use hardware verterx processing
            mesh_container->NumMatrixPalettes = min((caps.MaxVertexBlendMatrixIndex+1)/2, skin_info->GetNumBones());
            mesh_container->UseSoftwareVP = false;
        }

        hr = skin_info->ConvertToIndexedBlendedMesh(mesh_container->pOrgMesh, 0, mesh_container->NumMatrixPalettes,
                mesh_container->pAdjacency, NULL, NULL, NULL, &mesh_container->MaxBonesInflPerVertex,
                &mesh_container->NumAttrGroups, &mesh_container->pBoneCombBuffer, &mesh_container->MeshData.pMesh);

        return hr;
    }

    函数GenerateSkinnedMesh()判断当前网格容器是否包含蒙皮信息,如果当前网格模型中不包含蒙皮信息,则直接退出该函数。接下来确定所需要的矩阵调色板的容量,最后调用函数ConvertToIndexedBlendedMesh()根据初始网格模型提供的相应参数生成索引蒙皮网格模型。函数ConvertToIndexedBlendedMesh()的声明如下:
    Takes a mesh and returns a new mesh with per-vertex blend weights, indices, and a bone combination table. The table describes which bone palettes affect which subsets of the mesh.

    HRESULT ConvertToIndexedBlendedMesh(  LPD3DXMESH pMesh,  DWORD Options,  DWORD paletteSize,  CONST DWORD * pAdjacencyIn,  LPDWORD pAdjacencyOut,  DWORD * pFaceRemap,  LPD3DXBUFFER * ppVertexRemap,  DWORD * pMaxVertexInfl,  DWORD * pNumBoneCombinations,  LPD3DXBUFFER * ppBoneCombinationTable,  LPD3DXMESH * ppMesh);
    Parameters
    pMesh
    [in] The input mesh.
    Options
    [in] Currently unused.
    paletteSize
    [in] Number of bone matrices available for matrix palette skinning.
    pAdjacencyIn
    [in] Input mesh adjacency information.
    pAdjacencyOut
    [in] Output mesh adjacency information.
    pFaceRemap
    [out] An array of DWORDs, one per face, that identifies the original mesh face that corresponds to each face in the blended mesh. If the value supplied for this argument is NULL, face remap data is not returned.
    ppVertexRemap
    [out] Address of a pointer to an ID3DXBuffer interface, which contains a DWORD for each vertex that specifies how the new vertices map to the old vertices. This remap is useful if you need to alter external data based on the new vertex mapping. This parameter is optional; NULL may be used.
    pMaxVertexInfl
    [out] Pointer to a DWORD that will contain the maximum number of bone influences required per vertex for this skinning method.
    pNumBoneCombinations
    [out] Pointer to the number of bones in the bone combination table.
    ppBoneCombinationTable
    [out] Pointer to the bone combination table. The data is organized in a D3DXBONECOMBINATION structure.
    ppMesh
    [out] Pointer to the new mesh.
    Return Values
    If the method succeeds, the return value is D3D_OK. If the method fails, the return value can be D3DERR_INVALIDCALL.

    Remarks
    Each element in the remap arrays specifies the previous index for that position. For example, if a vertex was in position 3 but has been remapped to position 5, then the fifth element of pVertexRemap will contain 3.

    This method does not run on hardware that does not support fixed-function vertex blending.

    ----------------------------------------------
    事业是国家的,荣誉是单位的,成绩是领导的,工资是老婆的,财产是孩子的,错误是自己的。

    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2009/1/5 13:44:00
     
     卷积内核 帅哥哟,离线,有人找我吗?
      
      
      威望:8
      头衔:总统
      等级:博士二年级(版主)
      文章:3942
      积分:27590
      门派:XML.ORG.CN
      注册:2004/7/21

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给卷积内核发送一个短消息 把卷积内核加入好友 查看卷积内核的个人资料 搜索卷积内核在『 C/C++编程思想 』的所有贴子 访问卷积内核的主页 引用回复这个贴子 回复这个贴子 查看卷积内核的博客4
    发贴心情 
    cSkinMesh类的设计与实现

    cSkinMesh类的实现与cAnimMesh的实现基本相同,区别在以下几点。

    首先是在load_from_xfile()中增加了对网格模型骨骼矩阵的保存:


    HRESULT cSkinMesh::setup_bone_matrix_pointers(D3DXFRAME* frame)
    {    
        HRESULT hr;

        if(frame == NULL)
            return S_OK;

        if(frame->pMeshContainer != NULL)
        {
            hr = setup_bone_matrix_pointers_on_mesh(frame->pMeshContainer);

            if(FAILED(hr))
                return hr;
        }

        if(frame->pFrameSibling != NULL)
        {
            hr = setup_bone_matrix_pointers(frame->pFrameSibling);

            if(FAILED(hr))
                return hr;
        }

        if(frame->pFrameFirstChild != NULL)
        {
            hr = setup_bone_matrix_pointers(frame->pFrameFirstChild);

            if(FAILED(hr))
                return hr;
        }
        
        return S_OK;    
    }


    HRESULT cSkinMesh::setup_bone_matrix_pointers_on_mesh(D3DXMESHCONTAINER* base_mesh_container)
    {
        if(base_mesh_container == NULL)
            return S_OK;

        D3DXMESHCONTAINER_DERIVED* mesh_container = (D3DXMESHCONTAINER_DERIVED*) base_mesh_container;

        if(mesh_container->pSkinInfo != NULL)
        {
            UINT num_bones = mesh_container->pSkinInfo->GetNumBones();
            mesh_container->ppBoneMatrices = new D3DXMATRIX*[num_bones];

            if(mesh_container->ppBoneMatrices == NULL)
                return E_OUTOFMEMORY;

            for(UINT i = 0; i < num_bones; i++)
            {
                LPCSTR bone_name = mesh_container->pSkinInfo->GetBoneName(i);
                D3DXFRAME_DERIVED* frame = (D3DXFRAME_DERIVED*) D3DXFrameFind(m_root_frame, bone_name);

                if(frame == NULL)
                    return E_FAIL;

                mesh_container->ppBoneMatrices[i] = &frame->CombinedTransformMatrix;
            }
        }

        return S_OK;
    }


    HRESULT cSkinMesh::load_from_xfile(CONST WCHAR* wfilename)
    {
        HRESULT hr;

        WCHAR wpath[MAX_PATH];
        DXUTFindDXSDKMediaFileCch(wpath, sizeof(wpath) / sizeof(WCHAR), wfilename);

        V_RETURN(D3DXLoadMeshHierarchyFromXW(wpath, D3DXMESH_MANAGED, m_device, m_alloc_hierarchy, NULL, &m_root_frame,
                                             &m_anim_controller));

        V_RETURN(setup_bone_matrix_pointers(m_root_frame));

        V_RETURN(D3DXFrameCalculateBoundingSphere(m_root_frame, &m_object_center, &m_object_radius));

        return S_OK;
    }

      

    接下来是DrawMeshContainer()的实现,该函数负责当前网格容器中具体网格模型的渲染,其实现大致可以分为以下几个步骤:

    【1】如果当前网格模型是蒙皮网格模型

    (1)根据当前硬件设备的性能决定是否采用软件顶点处理模式。

    (2)激活索引顶点混合。

    (3)设置顶点混合所需要的矩阵索引数量。

    (4)渲染索引蒙皮网格模型,在具体渲染时,需要逐个属性组进行渲染,在渲染每个子网格时,首先需要设置骨骼混合矩阵、材质和数组。

    (5)恢复相关渲染状态。

    【2】如果当前网格模型不是蒙皮网格模型,则直接设置组合变换矩阵、材质和纹理,然后进行渲染。


    HRESULT cSkinMesh::draw_mesh_container(CONST D3DXMESHCONTAINER* base_mesh_container, CONST D3DXFRAME* base_frame)
    {
        HRESULT hr;

        D3DXMESHCONTAINER_DERIVED* mesh_container = (D3DXMESHCONTAINER_DERIVED*) base_mesh_container;
        D3DXFRAME_DERIVED* frame = (D3DXFRAME_DERIVED*) base_frame;

        if(mesh_container->pSkinInfo != NULL)
        {
            if(mesh_container->UseSoftwareVP)
            {
                V_RETURN(m_device->SetSoftwareVertexProcessing(TRUE));
            }
            
            if(mesh_container->MaxBonesInflPerVertex)
                m_device->SetRenderState(D3DRS_INDEXEDVERTEXBLENDENABLE, TRUE);

            if(mesh_container->MaxBonesInflPerVertex == 1)
                m_device->SetRenderState(D3DRS_VERTEXBLEND, D3DVBF_0WEIGHTS);
            else if(mesh_container->MaxBonesInflPerVertex == 2)
                m_device->SetRenderState(D3DRS_VERTEXBLEND, D3DVBF_1WEIGHTS);
            else if(mesh_container->MaxBonesInflPerVertex == 3)
                m_device->SetRenderState(D3DRS_VERTEXBLEND, D3DVBF_2WEIGHTS);
            else
                m_device->SetRenderState(D3DRS_VERTEXBLEND, D3DVBF_3WEIGHTS);

            D3DXBONECOMBINATION* bone_comb = (D3DXBONECOMBINATION*) mesh_container->pBoneCombBuffer->GetBufferPointer();

            for(UINT attr_index = 0; attr_index < mesh_container->NumAttrGroups; attr_index++)
            {
                // setup vertex index blending world matrix for every mesh group
                for(UINT palette_index = 0; palette_index < mesh_container->NumMatrixPalettes; palette_index++)
                {
                    UINT matrix_index = bone_comb[attr_index].BoneId[palette_index];

                    if(matrix_index != UINT_MAX)
                    {
                        D3DXMATRIX mat_palette;

                        D3DXMatrixMultiply(&mat_palette,
                                           mesh_container->ppBoneOffsetMatrices[matrix_index],
                                           mesh_container->ppBoneMatrices[matrix_index]);

                        m_device->SetTransform(D3DTS_WORLDMATRIX(palette_index), &mat_palette);
                    }
                }

                DWORD attr_id = bone_comb[attr_index].AttribId;

                m_device->SetMaterial(&mesh_container->pMaterials[attr_id].MatD3D);
                m_device->SetTexture(0, mesh_container->ppTextures[attr_id]);

                mesh_container->MeshData.pMesh->DrawSubset(attr_index);
            }

            // restore render state

            m_device->SetRenderState(D3DRS_INDEXEDVERTEXBLENDENABLE, FALSE);
            m_device->SetRenderState(D3DRS_VERTEXBLEND, D3DVBF_DISABLE);

            if(mesh_container->UseSoftwareVP)
            {
                V_RETURN(m_device->SetSoftwareVertexProcessing(FALSE));
            }
        }
        else
        {
            m_device->SetTransform(D3DTS_WORLD, &frame->CombinedTransformMatrix);

            for(UINT i = 0; i < mesh_container->NumMaterials; i++)
            {
                m_device->SetMaterial(&mesh_container->pMaterials[i].MatD3D);
                m_device->SetTexture(0, mesh_container->ppTextures[i]);

                mesh_container->MeshData.pMesh->DrawSubset(i);
            }
        }

        return S_OK;
    }

      

    蒙皮骨骼动画网格模型类的使用

    首先需要修改顶点处理模式,如果当前Direct3D设备使用纯硬件顶点处理模式,则改为混合顶点处理模式:

    // If video card does not support hardware transform and light, then uses sofaware mode.if((pCaps->DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) == 0) pDeviceSettings->BehaviorFlags = D3DCREATE_SOFTWARE_VERTEXPROCESSING;
    // !!important, change vertex processing to mixed mode.if(pDeviceSettings->BehaviorFlags & D3DCREATE_HARDWARE_VERTEXPROCESSING) pDeviceSettings->BehaviorFlags = D3DCREATE_MIXED_VERTEXPROCESSING;
    因为硬件可能不支持索引顶点混合,这时就需要使用软件顶点处理,所以在使用cSkinMesh类渲染蒙皮骨骼动画网格模型的程序中,如果Direct3D设备使用纯硬件顶点处理模式,则需要改为混合顶点处理模式,否则在调用IDirect3DDevice9::SetSoftwareProcessing()函数将顶点处理模式改为软件顶点处理模式时会出错。

    接下来在回调函数OnCreateDevice()中创建cSkinMesh类的实例:

    g_skin_mesh = new cSkinMesh();
    V_RETURN(g_skin_mesh->create(pd3dDevice, L"tiny.x"));

    再接下来在回调函数OnFrameRender()中渲染网格模型:

    V(g_skin_mesh->render(&g_mat_world, fElapsedTime));

    最后在回调函数OnDestroyDevice()中释放网格模型:

    g_skin_mesh->destroy();

    运行截图:

    按此在新窗口浏览图片

    ----------------------------------------------
    事业是国家的,荣誉是单位的,成绩是领导的,工资是老婆的,财产是孩子的,错误是自己的。

    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2009/1/5 13:44:00
     
     卷积内核 帅哥哟,离线,有人找我吗?
      
      
      威望:8
      头衔:总统
      等级:博士二年级(版主)
      文章:3942
      积分:27590
      门派:XML.ORG.CN
      注册:2004/7/21

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给卷积内核发送一个短消息 把卷积内核加入好友 查看卷积内核的个人资料 搜索卷积内核在『 C/C++编程思想 』的所有贴子 访问卷积内核的主页 引用回复这个贴子 回复这个贴子 查看卷积内核的博客5
    发贴心情 
    主程序:


    #include "dxstdafx.h"
    #include "resource.h"
    #include "SkinMesh.h"

    #pragma warning(disable : 4127 4995)

    #define IDC_TOGGLE_FULLSCREEN    1
    #define IDC_TOGGLE_REF            2
    #define IDC_CHANGE_DEVICE        3

    #define release_com(p)    do { if(p) { (p)->Release(); (p) = NULL; } } while(0)

    ID3DXFont*                    g_font;
    ID3DXSprite*                g_text_sprite;
    bool                        g_show_help;

    CDXUTDialogResourceManager    g_dlg_resource_manager;
    CD3DSettingsDlg                g_settings_dlg;
    CDXUTDialog                    g_button_dlg;

    cSkinMesh*                    g_skin_mesh;
    D3DXMATRIX                    g_mat_world;

    //--------------------------------------------------------------------------------------
    // Rejects any devices that aren't acceptable by returning false
    //--------------------------------------------------------------------------------------
    bool CALLBACK IsDeviceAcceptable( D3DCAPS9* pCaps, D3DFORMAT AdapterFormat,
                                      D3DFORMAT BackBufferFormat, bool bWindowed, void* pUserContext )
    {
        // Typically want to skip backbuffer formats that don't support alpha blending

        IDirect3D9* pD3D = DXUTGetD3DObject();

        if( FAILED( pD3D->CheckDeviceFormat( pCaps->AdapterOrdinal, pCaps->DeviceType, AdapterFormat,
                        D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING, D3DRTYPE_TEXTURE, BackBufferFormat ) ) )
            return false;

        return true;
    }


    //--------------------------------------------------------------------------------------
    // Before a device is created, modify the device settings as needed.
    //--------------------------------------------------------------------------------------
    bool CALLBACK ModifyDeviceSettings( DXUTDeviceSettings* pDeviceSettings, const D3DCAPS9* pCaps, void* pUserContext )
    {
        // If video card does not support hardware transform and light, then uses sofaware mode.
        if((pCaps->DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) == 0)
            pDeviceSettings->BehaviorFlags = D3DCREATE_SOFTWARE_VERTEXPROCESSING;

        // !!important, change vertex processing to mixed mode.
        if(pDeviceSettings->BehaviorFlags & D3DCREATE_HARDWARE_VERTEXPROCESSING)
            pDeviceSettings->BehaviorFlags = D3DCREATE_MIXED_VERTEXPROCESSING;

        static bool is_first_time = true;

        if(is_first_time)
        {
            is_first_time = false;

            // if using reference device, then pop a warning message box.
            if(pDeviceSettings->DeviceType == D3DDEVTYPE_REF)
                DXUTDisplaySwitchingToREFWarning();
        }

        return true;
    }


    //--------------------------------------------------------------------------------------
    // Create any D3DPOOL_MANAGED resources here
    //--------------------------------------------------------------------------------------
    HRESULT CALLBACK OnCreateDevice( IDirect3DDevice9* pd3dDevice,
                                     const D3DSURFACE_DESC* pBackBufferSurfaceDesc,
                                     void* pUserContext )
    {
        HRESULT    hr;

        V_RETURN(g_dlg_resource_manager.OnCreateDevice(pd3dDevice));
        V_RETURN(g_settings_dlg.OnCreateDevice(pd3dDevice));

        D3DXCreateFont(pd3dDevice, 18, 0, FW_BOLD, 1, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY,
                       DEFAULT_PITCH | FF_DONTCARE, L"Arial", &g_font);
        
        g_skin_mesh = new cSkinMesh();
        V_RETURN(g_skin_mesh->create(pd3dDevice, L"tiny.x"));

        return S_OK;
    }


    //--------------------------------------------------------------------------------------
    // Create any D3DPOOL_DEFAULT resources here
    //--------------------------------------------------------------------------------------
    HRESULT CALLBACK OnResetDevice( IDirect3DDevice9* pd3dDevice,
                                    const D3DSURFACE_DESC* pBackBufferSurfaceDesc,
                                    void* pUserContext )
    {
        HRESULT hr;

        V_RETURN(g_dlg_resource_manager.OnResetDevice());
        V_RETURN(g_settings_dlg.OnResetDevice());
        V_RETURN(g_font->OnResetDevice());
        V_RETURN(D3DXCreateSprite(pd3dDevice, &g_text_sprite));

        // set dialog position and size

        g_button_dlg.SetLocation(pBackBufferSurfaceDesc->Width - 170, 0);
        g_button_dlg.SetSize(170, 170);

        // setup view matrix

        D3DXMATRIX mat_view;
        D3DXVECTOR3 eye(0.0f, 0.0f, -1000.0f);
        D3DXVECTOR3  at(0.0f, 0.0f,  0.0f);
        D3DXVECTOR3  up(0.0f, 1.0f,  0.0f);

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

        // set projection matrix
        D3DXMATRIX mat_proj;    
        float aspect = (float)pBackBufferSurfaceDesc->Width / pBackBufferSurfaceDesc->Height;
        D3DXMatrixPerspectiveFovLH(&mat_proj, D3DX_PI/4, aspect, 1.0f, 2000.0f);
        pd3dDevice->SetTransform(D3DTS_PROJECTION, &mat_proj);

        // setup light
        
        D3DLIGHT9 light;
        ZeroMemory(&light, sizeof(D3DLIGHT9));

        light.Type       = D3DLIGHT_DIRECTIONAL;
        light.Diffuse.r  = 1.0f;
        light.Diffuse.g  = 1.0f;
        light.Diffuse.b  = 1.0f;
        light.Range         = 1000.0f;

        D3DXVECTOR3 light_dir(0.0f, -1.0f, 1.0f);    
        D3DXVec3Normalize((D3DXVECTOR3*) &light.Direction, &light_dir);
        pd3dDevice->SetLight(0, &light);
        pd3dDevice->LightEnable(0, TRUE);
        pd3dDevice->SetRenderState(D3DRS_LIGHTING, TRUE);

        pd3dDevice->SetRenderState(D3DRS_AMBIENT, 0x00505050);

        return S_OK;
    }

    //--------------------------------------------------------------------------------------
    // Release resources created in the OnResetDevice callback here
    //--------------------------------------------------------------------------------------
    void CALLBACK OnLostDevice( void* pUserContext )
    {
        g_dlg_resource_manager.OnLostDevice();
        g_settings_dlg.OnLostDevice();
        g_font->OnLostDevice();

        release_com(g_text_sprite);
    }


    //--------------------------------------------------------------------------------------
    // Release resources created in the OnCreateDevice callback here
    //--------------------------------------------------------------------------------------
    void CALLBACK OnDestroyDevice( void* pUserContext )
    {
        g_dlg_resource_manager.OnDestroyDevice();
        g_settings_dlg.OnDestroyDevice();    

        release_com(g_font);

        g_skin_mesh->destroy();
    }

    //--------------------------------------------------------------------------------------
    // Handle updates to the scene
    //--------------------------------------------------------------------------------------
    void CALLBACK OnFrameMove( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime, void* pUserContext )
    {
        D3DXMATRIX mat_trans, mat_rot;    
        
        D3DXMatrixTranslation(&mat_trans, 0.0f, 30.0f, -100.0f);
        D3DXMatrixRotationY(&mat_rot, timeGetTime() / 1000.0f);
            
        g_mat_world = mat_trans * mat_rot;
    }

    //--------------------------------------------------------------------------------------
    // Render the helper information
    //--------------------------------------------------------------------------------------
    void RenderText()
    {
        CDXUTTextHelper text_helper(g_font, g_text_sprite, 20);
        
        text_helper.Begin();

        // show frame and device states
        text_helper.SetInsertionPos(5, 5);
        text_helper.SetForegroundColor( D3DXCOLOR(1.0f, 0.475f, 0.0f, 1.0f) );
        text_helper.DrawTextLine( DXUTGetFrameStats(true) );
        text_helper.DrawTextLine( DXUTGetDeviceStats() );

        // show helper information
        
        const D3DSURFACE_DESC* surface_desc = DXUTGetBackBufferSurfaceDesc();

        if(g_show_help)
        {
            text_helper.SetInsertionPos(10, surface_desc->Height - 15 * 6);
            text_helper.SetForegroundColor( D3DXCOLOR(1.0f, 0.475f, 0.0f, 1.0f) );
            text_helper.DrawTextLine(L"Controls (F1 to hide):");
            
            text_helper.SetInsertionPos(40, surface_desc->Height - 15 * 4);
            text_helper.DrawTextLine(L"Quit: ESC");
        }
        else
        {
            text_helper.SetInsertionPos(10, surface_desc->Height - 15 * 4);
            text_helper.SetForegroundColor( D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f) );
            text_helper.DrawTextLine(L"Press F1 for help");
        }

        text_helper.End();
    }

    //--------------------------------------------------------------------------------------
    // Render the scene
    //--------------------------------------------------------------------------------------
    void CALLBACK OnFrameRender( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime, void* pUserContext )
    {
        HRESULT hr;

        if(g_settings_dlg.IsActive())
        {
            g_settings_dlg.OnRender(fElapsedTime);
            return;
        }

        // Clear the render target and the zbuffer
        V( pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_ARGB(0, 0, 0, 0), 1.0f, 0) );

        // Render the scene
        if( SUCCEEDED( pd3dDevice->BeginScene() ) )
        {                                    
            V(g_skin_mesh->render(&g_mat_world, fElapsedTime));
            RenderText();
            V(g_button_dlg.OnRender(fElapsedTime));

            V( pd3dDevice->EndScene() );
        }
    }


    //--------------------------------------------------------------------------------------
    // Handle messages to the application
    //--------------------------------------------------------------------------------------
    LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam,
                              bool* pbNoFurtherProcessing, void* pUserContext )
    {
        *pbNoFurtherProcessing = g_dlg_resource_manager.MsgProc(hWnd, uMsg, wParam, lParam);
        if(*pbNoFurtherProcessing)
            return 0;

        if(g_settings_dlg.IsActive())
        {
            g_settings_dlg.MsgProc(hWnd, uMsg, wParam, lParam);
            return 0;
        }

        *pbNoFurtherProcessing = g_button_dlg.MsgProc(hWnd, uMsg, wParam, lParam);
        if(*pbNoFurtherProcessing)
            return 0;

        return 0;
    }


    //--------------------------------------------------------------------------------------
    // Handle keybaord event
    //--------------------------------------------------------------------------------------
    void CALLBACK OnKeyboardProc(UINT charater, bool is_key_down, bool is_alt_down, void* user_context)
    {
        if(is_key_down)
        {
            switch(charater)
            {
            case VK_F1:
                g_show_help = !g_show_help;
                break;
            }
        }
    }

    //--------------------------------------------------------------------------------------
    // Handle events for controls
    //--------------------------------------------------------------------------------------
    void CALLBACK OnGUIEvent(UINT event, int control_id, CDXUTControl* control, void* user_context)
    {
        switch(control_id)
        {
        case IDC_TOGGLE_FULLSCREEN:
            DXUTToggleFullScreen();
            break;

        case IDC_TOGGLE_REF:
            DXUTToggleREF();
            break;

        case IDC_CHANGE_DEVICE:
            g_settings_dlg.SetActive(true);
            break;
        }
    }

    //--------------------------------------------------------------------------------------
    // Initialize dialogs
    //--------------------------------------------------------------------------------------
    void InitDialogs()
    {
        g_settings_dlg.Init(&g_dlg_resource_manager);
        g_button_dlg.Init(&g_dlg_resource_manager);

        g_button_dlg.SetCallback(OnGUIEvent);

        int x = 35, y = 10, width = 125, height = 22;

        g_button_dlg.AddButton(IDC_TOGGLE_FULLSCREEN, L"Toggle full screen", x, y,         width, height);
        g_button_dlg.AddButton(IDC_TOGGLE_REF,          L"Toggle REF (F3)",     x, y += 24, width, height);
        g_button_dlg.AddButton(IDC_CHANGE_DEVICE,      L"Change device (F2)", x, y += 24, width, height, VK_F2);    
    }

    //--------------------------------------------------------------------------------------
    // Initialize everything and go into a render loop
    //--------------------------------------------------------------------------------------
    INT WINAPI WinMain( HINSTANCE, HINSTANCE, LPSTR, int )
    {
        // Enable run-time memory check for debug builds.
    #if defined(DEBUG) | defined(_DEBUG)
        _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
    #endif

        // Set the callback functions
        DXUTSetCallbackDeviceCreated( OnCreateDevice );
        DXUTSetCallbackDeviceReset( OnResetDevice );
        DXUTSetCallbackDeviceLost( OnLostDevice );
        DXUTSetCallbackDeviceDestroyed( OnDestroyDevice );
        DXUTSetCallbackMsgProc( MsgProc );
        DXUTSetCallbackFrameRender( OnFrameRender );
        DXUTSetCallbackFrameMove( OnFrameMove );
        DXUTSetCallbackKeyboard(OnKeyboardProc);
       
        // TODO: Perform any application-level initialization here
        InitDialogs();

        // Initialize DXUT and create the desired Win32 window and Direct3D device for the application
        DXUTInit( true, true, true ); // Parse the command line, handle the default hotkeys, and show msgboxes
        DXUTSetCursorSettings( true, true ); // Show the cursor and clip it when in full screen
        DXUTCreateWindow( L"Use Skin Mesh" );
        DXUTCreateDevice( D3DADAPTER_DEFAULT, true, 640, 480, IsDeviceAcceptable, ModifyDeviceSettings );

        // Start the render loop
        DXUTMainLoop();

        // TODO: Perform any application-level cleanup here

        return DXUTGetExitCode();
    }

    [B][URL=http://www.cppblog.com/Files/changingnow/UseSkinMesh.rar]下载示例工程[/URL][/B]

    ----------------------------------------------
    事业是国家的,荣誉是单位的,成绩是领导的,工资是老婆的,财产是孩子的,错误是自己的。

    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2009/1/5 13:45:00
     
     卷积内核 帅哥哟,离线,有人找我吗?
      
      
      威望:8
      头衔:总统
      等级:博士二年级(版主)
      文章:3942
      积分:27590
      门派:XML.ORG.CN
      注册:2004/7/21

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给卷积内核发送一个短消息 把卷积内核加入好友 查看卷积内核的个人资料 搜索卷积内核在『 C/C++编程思想 』的所有贴子 访问卷积内核的主页 引用回复这个贴子 回复这个贴子 查看卷积内核的博客6
    发贴心情 
    一个网格模型中可以包含多个动画集,在渲染网格时通过动画控制器可以在各个动画集之间进行切换,从而可以在渲染网格模型时根据具体情况播放不同的动画。这里将具有多个骨骼动画的网格模型称为"多骨骼动画网格模型",当然骨骼动画网格模型也完全可以具有蒙皮信息,下面的示例程序演示了渲染多骨骼动画网格模型时骨骼动画之间的切换,骨骼动画间的切换是通过动画控制器来完成的。

    在示例程序MultiAnimMesh中渲染的网格模型具有4个动画集,即具有4个动作,通过按下数字键"1" ~ "4"在4个动作之间进行切换:

    case 49: // press key "1" g_skin_mesh->m_anim_controller->GetAnimationSetByName("Walk", &g_anim_set); g_skin_mesh->m_anim_controller->SetTrackAnimationSet(0, g_anim_set);  break;
    case 50: // press key "2" g_skin_mesh->m_anim_controller->GetAnimationSetByName("Jog", &g_anim_set); g_skin_mesh->m_anim_controller->SetTrackAnimationSet(0, g_anim_set);  break; 
    case 51: // press key "3" g_skin_mesh->m_anim_controller->GetAnimationSetByName("Loiter", &g_anim_set); g_skin_mesh->m_anim_controller->SetTrackAnimationSet(0, g_anim_set);  break;
    case 52: // press key "4" g_skin_mesh->m_anim_controller->GetAnimationSetByName("Wave", &g_anim_set); g_skin_mesh->m_anim_controller->SetTrackAnimationSet(0, g_anim_set);  break;
    GetAnimationSetByName()根据名称取得动画播放集:

    Gets an animation set, given its name.

    HRESULT GetAnimationSetByName(  LPCSTR pName,  LPD3DXANIMATIONSET * ppAnimSet);
    Parameters
    pName
    [in] String containing the name of the animation set.
    ppAnimSet
    [out] Pointer to the ID3DXAnimationSet animation set.
    Return Values
    If the method succeeds, the return value is S_OK. If the method fails, the following value will be returned: D3DERR_INVALIDCALL.

    Remarks
    The animation controller contains an array of animation sets. This method returns an animation set that has the given name.

    SetTrackAnimationSet()设置要播放的动画集:

    Applies the animation set to the specified track.

    HRESULT SetTrackAnimationSet(  UINT Track,  LPD3DXANIMATIONSET pAnimSet);
    Parameters
    Track
    [in] Identifier of the track to which the animation set is applied.
    pAnimSet
    [in] Pointer to the ID3DXAnimationSet animation set to be added to the track.
    Return Values
    If the method succeeds, the return value is S_OK. If the method fails, the return value can be one of the following values: D3DERR_INVALIDCALL, E_OUTOFMEMORY.

    Remarks
    This method sets the animation set to the specified track for mixing. The animation set for each track is blended according to the track weight and speed when ID3DXAnimationController::AdvanceTime is called.

    运行效果图:

    按此在新窗口浏览图片

    步行

    按此在新窗口浏览图片

    跑步

    按此在新窗口浏览图片

    观望


    按此在新窗口浏览图片

    挥手

    ----------------------------------------------
    事业是国家的,荣誉是单位的,成绩是领导的,工资是老婆的,财产是孩子的,错误是自己的。

    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2009/1/5 13:45:00
     
     卷积内核 帅哥哟,离线,有人找我吗?
      
      
      威望:8
      头衔:总统
      等级:博士二年级(版主)
      文章:3942
      积分:27590
      门派:XML.ORG.CN
      注册:2004/7/21

    姓名:(无权查看)
    城市:(无权查看)
    院校:(无权查看)
    给卷积内核发送一个短消息 把卷积内核加入好友 查看卷积内核的个人资料 搜索卷积内核在『 C/C++编程思想 』的所有贴子 访问卷积内核的主页 引用回复这个贴子 回复这个贴子 查看卷积内核的博客7
    发贴心情 
    主程序:


    #include "dxstdafx.h"
    #include "resource.h"
    #include "SkinMesh.h"

    #pragma warning(disable : 4127 4995)

    #define IDC_TOGGLE_FULLSCREEN    1
    #define IDC_TOGGLE_REF            2
    #define IDC_CHANGE_DEVICE        3

    #define release_com(p)    do { if(p) { (p)->Release(); (p) = NULL; } } while(0)

    ID3DXFont*                    g_font;
    ID3DXSprite*                g_text_sprite;
    bool                        g_show_help = true;

    CDXUTDialogResourceManager    g_dlg_resource_manager;
    CD3DSettingsDlg                g_settings_dlg;
    CDXUTDialog                    g_button_dlg;

    cSkinMesh*                    g_skin_mesh;
    ID3DXAnimationSet*            g_anim_set;
    D3DXMATRIX                    g_mat_world;

    //--------------------------------------------------------------------------------------
    // Rejects any devices that aren't acceptable by returning false
    //--------------------------------------------------------------------------------------
    bool CALLBACK IsDeviceAcceptable( D3DCAPS9* pCaps, D3DFORMAT AdapterFormat,
                                      D3DFORMAT BackBufferFormat, bool bWindowed, void* pUserContext )
    {
        // Typically want to skip backbuffer formats that don't support alpha blending

        IDirect3D9* pD3D = DXUTGetD3DObject();

        if( FAILED( pD3D->CheckDeviceFormat( pCaps->AdapterOrdinal, pCaps->DeviceType, AdapterFormat,
                        D3DUSAGE_QUERY_POSTPIXELSHADER_BLENDING, D3DRTYPE_TEXTURE, BackBufferFormat ) ) )
            return false;

        return true;
    }


    //--------------------------------------------------------------------------------------
    // Before a device is created, modify the device settings as needed.
    //--------------------------------------------------------------------------------------
    bool CALLBACK ModifyDeviceSettings( DXUTDeviceSettings* pDeviceSettings, const D3DCAPS9* pCaps, void* pUserContext )
    {
        // If video card does not support hardware transform and light, then uses sofaware mode.
        if((pCaps->DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) == 0)
            pDeviceSettings->BehaviorFlags = D3DCREATE_SOFTWARE_VERTEXPROCESSING;

        // !!important, change vertex processing to mixed mode.
        if(pDeviceSettings->BehaviorFlags & D3DCREATE_HARDWARE_VERTEXPROCESSING)
            pDeviceSettings->BehaviorFlags = D3DCREATE_MIXED_VERTEXPROCESSING;

        static bool is_first_time = true;

        if(is_first_time)
        {
            is_first_time = false;

            // if using reference device, then pop a warning message box.
            if(pDeviceSettings->DeviceType == D3DDEVTYPE_REF)
                DXUTDisplaySwitchingToREFWarning();
        }

        return true;
    }


    //--------------------------------------------------------------------------------------
    // Create any D3DPOOL_MANAGED resources here
    //--------------------------------------------------------------------------------------
    HRESULT CALLBACK OnCreateDevice( IDirect3DDevice9* pd3dDevice,
                                     const D3DSURFACE_DESC* pBackBufferSurfaceDesc,
                                     void* pUserContext )
    {
        HRESULT    hr;

        V_RETURN(g_dlg_resource_manager.OnCreateDevice(pd3dDevice));
        V_RETURN(g_settings_dlg.OnCreateDevice(pd3dDevice));

        D3DXCreateFont(pd3dDevice, 18, 0, FW_BOLD, 1, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY,
                       DEFAULT_PITCH | FF_DONTCARE, L"Arial", &g_font);
        
        g_skin_mesh = new cSkinMesh();
        V_RETURN(g_skin_mesh->create(pd3dDevice, L"tiny_4anim.x"));

        return S_OK;
    }


    //--------------------------------------------------------------------------------------
    // Create any D3DPOOL_DEFAULT resources here
    //--------------------------------------------------------------------------------------
    HRESULT CALLBACK OnResetDevice( IDirect3DDevice9* pd3dDevice,
                                    const D3DSURFACE_DESC* pBackBufferSurfaceDesc,
                                    void* pUserContext )
    {
        HRESULT hr;

        V_RETURN(g_dlg_resource_manager.OnResetDevice());
        V_RETURN(g_settings_dlg.OnResetDevice());
        V_RETURN(g_font->OnResetDevice());
        V_RETURN(D3DXCreateSprite(pd3dDevice, &g_text_sprite));

        // set dialog position and size

        g_button_dlg.SetLocation(pBackBufferSurfaceDesc->Width - 170, 0);
        g_button_dlg.SetSize(170, 170);

        // setup view matrix

        D3DXMATRIX mat_view;
        D3DXVECTOR3 eye(0.0f, 0.0f, -1000.0f);
        D3DXVECTOR3  at(0.0f, 0.0f,  0.0f);
        D3DXVECTOR3  up(0.0f, 1.0f,  0.0f);

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

        // set projection matrix
        D3DXMATRIX mat_proj;    
        float aspect = (float)pBackBufferSurfaceDesc->Width / pBackBufferSurfaceDesc->Height;
        D3DXMatrixPerspectiveFovLH(&mat_proj, D3DX_PI/4, aspect, 1.0f, 2000.0f);
        pd3dDevice->SetTransform(D3DTS_PROJECTION, &mat_proj);

        // setup light
        
        D3DLIGHT9 light;
        ZeroMemory(&light, sizeof(D3DLIGHT9));

        light.Type       = D3DLIGHT_DIRECTIONAL;
        light.Diffuse.r  = 1.0f;
        light.Diffuse.g  = 1.0f;
        light.Diffuse.b  = 1.0f;
        light.Range         = 1000.0f;

        D3DXVECTOR3 light_dir(-1.0f, -1.0f, 1.0f);    
        D3DXVec3Normalize((D3DXVECTOR3*) &light.Direction, &light_dir);
        pd3dDevice->SetLight(0, &light);
        pd3dDevice->LightEnable(0, TRUE);
        pd3dDevice->SetRenderState(D3DRS_LIGHTING, TRUE);

        pd3dDevice->SetRenderState(D3DRS_AMBIENT, 0x00505050);

        return S_OK;
    }

    //--------------------------------------------------------------------------------------
    // Release resources created in the OnResetDevice callback here
    //--------------------------------------------------------------------------------------
    void CALLBACK OnLostDevice( void* pUserContext )
    {
        g_dlg_resource_manager.OnLostDevice();
        g_settings_dlg.OnLostDevice();
        g_font->OnLostDevice();

        release_com(g_text_sprite);
    }


    //--------------------------------------------------------------------------------------
    // Release resources created in the OnCreateDevice callback here
    //--------------------------------------------------------------------------------------
    void CALLBACK OnDestroyDevice( void* pUserContext )
    {
        g_dlg_resource_manager.OnDestroyDevice();
        g_settings_dlg.OnDestroyDevice();    

        release_com(g_font);

        g_skin_mesh->destroy();
    }

    //--------------------------------------------------------------------------------------
    // Handle updates to the scene
    //--------------------------------------------------------------------------------------
    void CALLBACK OnFrameMove( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime, void* pUserContext )
    {
        D3DXMATRIX mat_trans, mat_rot_x, mat_rot_y;    
        
        D3DXMatrixRotationX(&mat_rot_x, -D3DX_PI / 2);
        D3DXMatrixRotationY(&mat_rot_y, timeGetTime() / 1000.0f);
        D3DXMatrixTranslation(&mat_trans, 0.0f, -250.0f, 0.0f);
                
        g_mat_world = mat_rot_x * mat_rot_y * mat_trans;
    }

    //--------------------------------------------------------------------------------------
    // Render the helper information
    //--------------------------------------------------------------------------------------
    void RenderText()
    {
        CDXUTTextHelper text_helper(g_font, g_text_sprite, 20);
        
        text_helper.Begin();

        // show frame and device states
        text_helper.SetInsertionPos(5, 5);
        text_helper.SetForegroundColor( D3DXCOLOR(1.0f, 0.475f, 0.0f, 1.0f) );
        text_helper.DrawTextLine( DXUTGetFrameStats(true) );
        text_helper.DrawTextLine( DXUTGetDeviceStats() );

        // show helper information
        
        const D3DSURFACE_DESC* surface_desc = DXUTGetBackBufferSurfaceDesc();

        if(g_show_help)
        {
            text_helper.SetInsertionPos(10, surface_desc->Height - 15 * 10);
            text_helper.SetForegroundColor( D3DXCOLOR(1.0f, 0.475f, 0.0f, 1.0f) );
            text_helper.DrawTextLine(L"Controls (F1 to hide):");
            text_helper.DrawTextLine(L"Quit: ESC\n");

            text_helper.SetInsertionPos(10, surface_desc->Height - 15 * 6);        
            text_helper.DrawTextLine(L"1: walk");
            text_helper.DrawTextLine(L"2: jog");
            text_helper.DrawTextLine(L"3: loiter");
            text_helper.DrawTextLine(L"4: wave");
        }
        else
        {
            text_helper.SetInsertionPos(10, surface_desc->Height - 15 * 4);
            text_helper.SetForegroundColor( D3DXCOLOR(1.0f, 1.0f, 1.0f, 1.0f) );
            text_helper.DrawTextLine(L"Press F1 for help");
        }

        text_helper.End();
    }

    //--------------------------------------------------------------------------------------
    // Render the scene
    //--------------------------------------------------------------------------------------
    void CALLBACK OnFrameRender( IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime, void* pUserContext )
    {
        HRESULT hr;

        if(g_settings_dlg.IsActive())
        {
            g_settings_dlg.OnRender(fElapsedTime);
            return;
        }

        // Clear the render target and the zbuffer
        V( pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_ARGB(0, 0, 0, 0), 1.0f, 0) );

        // Render the scene
        if( SUCCEEDED( pd3dDevice->BeginScene() ) )
        {                                    
            V(g_skin_mesh->render(&g_mat_world, fElapsedTime));
            RenderText();
            V(g_button_dlg.OnRender(fElapsedTime));

            V( pd3dDevice->EndScene() );
        }
    }


    //--------------------------------------------------------------------------------------
    // Handle messages to the application
    //--------------------------------------------------------------------------------------
    LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam,
                              bool* pbNoFurtherProcessing, void* pUserContext )
    {
        *pbNoFurtherProcessing = g_dlg_resource_manager.MsgProc(hWnd, uMsg, wParam, lParam);
        if(*pbNoFurtherProcessing)
            return 0;

        if(g_settings_dlg.IsActive())
        {
            g_settings_dlg.MsgProc(hWnd, uMsg, wParam, lParam);
            return 0;
        }

        *pbNoFurtherProcessing = g_button_dlg.MsgProc(hWnd, uMsg, wParam, lParam);
        if(*pbNoFurtherProcessing)
            return 0;

        return 0;
    }


    //--------------------------------------------------------------------------------------
    // Handle keybaord event
    //--------------------------------------------------------------------------------------
    void CALLBACK OnKeyboardProc(UINT charater, bool is_key_down, bool is_alt_down, void* user_context)
    {
        if(is_key_down)
        {
            switch(charater)
            {
            case VK_F1:
                g_show_help = !g_show_help;
                break;

            case 49:    // press key "1"
                g_skin_mesh->m_anim_controller->GetAnimationSetByName("Walk", &g_anim_set);
                g_skin_mesh->m_anim_controller->SetTrackAnimationSet(0, g_anim_set);    
                break;

            case 50:    // press key "2"
                g_skin_mesh->m_anim_controller->GetAnimationSetByName("Jog", &g_anim_set);
                g_skin_mesh->m_anim_controller->SetTrackAnimationSet(0, g_anim_set);    
                break;    

            case 51:    // press key "3"
                g_skin_mesh->m_anim_controller->GetAnimationSetByName("Loiter", &g_anim_set);
                g_skin_mesh->m_anim_controller->SetTrackAnimationSet(0, g_anim_set);    
                break;

            case 52:    // press key "4"
                g_skin_mesh->m_anim_controller->GetAnimationSetByName("Wave", &g_anim_set);
                g_skin_mesh->m_anim_controller->SetTrackAnimationSet(0, g_anim_set);    
                break;
            }
        }
    }

    //--------------------------------------------------------------------------------------
    // Handle events for controls
    //--------------------------------------------------------------------------------------
    void CALLBACK OnGUIEvent(UINT event, int control_id, CDXUTControl* control, void* user_context)
    {
        switch(control_id)
        {
        case IDC_TOGGLE_FULLSCREEN:
            DXUTToggleFullScreen();
            break;

        case IDC_TOGGLE_REF:
            DXUTToggleREF();
            break;

        case IDC_CHANGE_DEVICE:
            g_settings_dlg.SetActive(true);
            break;
        }
    }

    //--------------------------------------------------------------------------------------
    // Initialize dialogs
    //--------------------------------------------------------------------------------------
    void InitDialogs()
    {
        g_settings_dlg.Init(&g_dlg_resource_manager);
        g_button_dlg.Init(&g_dlg_resource_manager);

        g_button_dlg.SetCallback(OnGUIEvent);

        int x = 35, y = 10, width = 125, height = 22;

        g_button_dlg.AddButton(IDC_TOGGLE_FULLSCREEN, L"Toggle full screen", x, y,         width, height);
        g_button_dlg.AddButton(IDC_TOGGLE_REF,          L"Toggle REF (F3)",     x, y += 24, width, height);
        g_button_dlg.AddButton(IDC_CHANGE_DEVICE,      L"Change device (F2)", x, y += 24, width, height, VK_F2);    
    }

    //--------------------------------------------------------------------------------------
    // Initialize everything and go into a render loop
    //--------------------------------------------------------------------------------------
    INT WINAPI WinMain( HINSTANCE, HINSTANCE, LPSTR, int )
    {
        // Enable run-time memory check for debug builds.
    #if defined(DEBUG) | defined(_DEBUG)
        _CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
    #endif

        // Set the callback functions
        DXUTSetCallbackDeviceCreated( OnCreateDevice );
        DXUTSetCallbackDeviceReset( OnResetDevice );
        DXUTSetCallbackDeviceLost( OnLostDevice );
        DXUTSetCallbackDeviceDestroyed( OnDestroyDevice );
        DXUTSetCallbackMsgProc( MsgProc );
        DXUTSetCallbackFrameRender( OnFrameRender );
        DXUTSetCallbackFrameMove( OnFrameMove );
        DXUTSetCallbackKeyboard(OnKeyboardProc);
       
        // TODO: Perform any application-level initialization here
        InitDialogs();

        // Initialize DXUT and create the desired Win32 window and Direct3D device for the application
        DXUTInit( true, true, true ); // Parse the command line, handle the default hotkeys, and show msgboxes
        DXUTSetCursorSettings( true, true ); // Show the cursor and clip it when in full screen
        DXUTCreateWindow( L"Multi Animation Mesh" );
        DXUTCreateDevice( D3DADAPTER_DEFAULT, true, 640, 480, IsDeviceAcceptable, ModifyDeviceSettings );

        // Start the render loop
        DXUTMainLoop();

        // TODO: Perform any application-level cleanup here

        return DXUTGetExitCode();
    }

    [B][URL=http://www.cppblog.com/Files/changingnow/MultiAnimMesh.rar]下载示例工程[/URL][/B]

    ----------------------------------------------
    事业是国家的,荣誉是单位的,成绩是领导的,工资是老婆的,财产是孩子的,错误是自己的。

    点击查看用户来源及管理<br>发贴IP:*.*.*.* 2009/1/5 13:46:00
     
     GoogleAdSense
      
      
      等级:大一新生
      文章:1
      积分:50
      门派:无门无派
      院校:未填写
      注册:2007-01-01
    给Google AdSense发送一个短消息 把Google AdSense加入好友 查看Google AdSense的个人资料 搜索Google AdSense在『 C/C++编程思想 』的所有贴子 访问Google AdSense的主页 引用回复这个贴子 回复这个贴子 查看Google AdSense的博客广告
    2024/4/28 4:53:33

    本主题贴数7,分页: [1]

    管理选项修改tag | 锁定 | 解锁 | 提升 | 删除 | 移动 | 固顶 | 总固顶 | 奖励 | 惩罚 | 发布公告
    W3C Contributing Supporter! W 3 C h i n a ( since 2003 ) 旗 下 站 点
    苏ICP备05006046号《全国人大常委会关于维护互联网安全的决定》《计算机信息网络国际联网安全保护管理办法》
    279.297ms