以文本方式查看主题 - 计算机科学论坛 (http://bbs.xml.org.cn/index.asp) -- 『 C/C++编程思想 』 (http://bbs.xml.org.cn/list.asp?boardid=61) ---- 网格模型高级技术(1) (http://bbs.xml.org.cn/dispbbs.asp?boardid=61&rootid=&id=70511) |
-- 作者:卷积内核 -- 发布时间:12/15/2008 3:25:00 PM -- 网格模型高级技术(1) 在三维图形程序设计中,网格模型占有非常重要的地位,而且也是比较复杂的部分,特别是包含动画和蒙皮信息的网格模型。
.x文件格式分析 .x文件格式最初是为传统的Direct3D保留模式而设计的,在DirectX 6.0问世后,针对立即模式对它作过一次扩展。要想在Direct3D程序中灵活自如地使用网格模型,应当深入理解.x文件格式。 .x文件是由模板(template)驱动的,模板定义了如何存储一个数据对象,这样用户便可以自己定义具体的格式。Direct3D预定义了许多模板,这些预定义的模板位于rmxftmpl.h中,模板标识符都在rmxfguid.h中,通用文件DXUTMesh.cpp包含了这两个头文件。模板所允许的数据类型称为可选成员(optional member),这些可选成员作为数据对象的子对象来保存,子对象可以是另一种数据类型或对先前数据对象的引用,或是一个二进制对象。 来看一个.x文件(cube_1.x)的完整内容: xof 0302txt 0064 第一行文件头中的 "xof"告诉程序,它加载的文件是一个.x文件,"0302"表示它使用的是DirectX 3.2 版本的模板,"txt"表示这些数据是以文本形式存储的,"0064"定义了浮点数的位数是64位。 文件头后面的一个数据块涉及了模板和数据对象等内容。一个模板和一个数据对象之间的差异在于所有的模板都是以一个template单词开始,模板看起来很像一个C语言的结构定义,数据对象就是那些模板的实例。使用模板定义包含在.x文件里的数据对象(一个模板定义了数据对象的布局),每个模板都可以通过一个数据类型的集合去定义并容纳任何类型的数据。同时,任何数据类型的组合都可以在一个模板里使用。 模板header的定义如下: template Header { <3D82AB43-62DA-11cf-AB39-0020AF71E433> WORD major; WORD minor; DWORD flags;} .x文件中涉及模板的概念,它由四部分组成:第一部分是模板的名字,可是由数字、字符、下划线构成,但不能以数字开头,第二部分是GUID(Global Unique Identifier,全局唯一标识符),第三部分由各个数据项构成,最后一部分用于控制模板的限制程度,一个模板可以是开放的、闭合的或受限的。开放模板的定义在结束部位有一个待展开的方括号[...]表示它可以包含其他数据类型,封闭模板不能包含其他任何数据类型,受限模板只能包含特定的数据类型。模板的使用与结构体有相似之处。 一般情况下,.x文件都至少包含一个Mesh模板,其定义如下: Defines a simple mesh. The first array is a list of vertices, and the second array defines the faces of the mesh by indexing into the vertex array. template Mesh{ <3D82AB44-62DA-11CF-AB39-0020AF71E433> DWORD nVertices; array Vector vertices[nVertices]; DWORD nFaces; array MeshFace faces[nFaces]; [...]} nVertices - Number of vertices. Defines a vector. template Vector { < 3D82AB5E-62DA-11cf-AB39-0020AF71E433 > float x; float y; float z; } template MeshFace{ < 3D82AB5F-62DA-11cf-AB39-0020AF71E433 > DWORD nFaceVertexIndices; array DWORD faceVertexIndices[nFaceVertexIndices];} nFaceVertexIndices - Number of indices. |
-- 作者:卷积内核 -- 发布时间:12/15/2008 3:26:00 PM -- 我们在cube_1.x的基础上添加材质、法线和纹理,构成cube_2.x: xof 0302txt 0064 可以看到在Mesh模板中嵌套着一个子模板MeshMaterialList,它是Mesh模板的一部分,用来将每个面与材质相关联,其定义如下: Used in a mesh object to specify which material applies to which faces. The nMaterials member specifies how many materials are present, and materials specify which material to apply. template MeshMaterialList{ < F6F23F42-7686-11CF-8F52-0040333594A3 > DWORD nMaterials; DWORD nFaceIndexes; array DWORD faceIndexes[nFaceIndexes]; [Material <3D82AB4D-62DA-11CF-AB39-0020AF71E433>]} nMaterials - A DWORD. The number of materials. Defines a basic material color that can be applied to either a complete mesh or a mesh's individual faces. The power is the specular exponent of the material. Note The ambient color requires an alpha component. TextureFilename is an optional data object. If this object is not present, the face is untextured. template Material{ < 3D82AB4D-62DA-11CF-AB39-0020AF71E433 > ColorRGBA faceColor; FLOAT power; ColorRGB specularColor; ColorRGB emissiveColor; [...]} faceColor - Face color. A ColorRGBA template. Defines a color object with an alpha component. This is used for the face color in the material template definition. template ColorRGBA{ < 35FF44E0-6C7C-11cf-8F52-0040333594A3 > float red; float green; float blue; float alpha;} template ColorRGB{ < D3E16E81-7835-11cf-8F52-0040333594A3 > float red; float green; float blue;} 在cube_2.x中,首先定义了两个材质RedMaterial和GreenMaterial: Material RedMaterial { //第一块材料 1.000000;0.000000;0.000000;1.000000;; // R = 1.0, G = 0.0, B = 0.0 0.000000; 0.000000;0.000000;0.000000;; 0.000000;0.000000;0.000000;; //网格材质列表MeshMaterialList { 2; //使用材质的数量:2块材质 12; //为12个面指定材质 0, //为前6个面使用第一块材质 0, 0, 0, 0, 0, 1, //为后面的6个面使用第二块材质 1, 1, 1, 1, 1;; 在光照模型运算时需要用到法向量,法向量分为面法向量和顶点法向量。在基于逐顶点计算的光照模型中,需要使用顶点法向量。通常顶点法向量的计算过程是:先将共享该顶点的几个面的面法向量相加并除以共享该顶点的面的个数,接着归一化这个结果。模板MeshNormals用来指定法向量: Defines normals for a mesh. The first array of vectors is the normal vectors themselves, and the second array is an array of indexes specifying which normals should be applied to a given face. The value of the nFaceNormals member should be equal to the number of faces in a mesh. template MeshNormals{ < F6F23F43-7686-11cf-8F52-0040333594A3 > DWORD nNormals; array Vector normals[nNormals]; DWORD nFaceNormals; array MeshFace faceNormals[nFaceNormals];} nNormals - Number of normals. //顶点法线MeshNormals { 8; //定义8个法线向量 0.333333;0.666667;-0.666667;, -0.816497;0.408248;-0.408248;, -0.333333;0.666667;0.666667;, 0.816497;0.408248;0.408248;, 0.666667;-0.666667;-0.333333;, -0.408248;-0.408248;-0.816497;, -0.666667;-0.666667;0.333333;, 0.408248;-0.408248;0.816497;; Enables you to specify the file name of a texture to apply to a mesh or a face. This template should appear within a material object. template TextureFilename { < A42790E1-7810-11cf-8F52-0040333594A3 > string filename; } 在使用TextureFilename模板时,只需要使用字符串filename指定一个纹理文件名即可,但要将这幅纹理映射到网格模型中,还需要指定纹理坐标: Defines a mesh's texture coordinates. template MeshTextureCoords{ < F6F23F40-7686-11cf-8F52-0040333594A3 > DWORD nTextureCoords; array Coords2d textureCoords[nTextureCoords] ;} nTextureCoords - Number of texture coordinates. template Coords2d{ < F6F23F44-7686-11cf-8F52-0040333594A3 > float u; float v;} //纹理坐标MeshTextureCoords { 8; //定义8对纹理坐标 0.000000;1.000000; 1.000000;1.000000; 0.000000;1.000000; 1.000000;1.000000; 0.000000;0.000000; 1.000000;0.000000; 0.000000;0.000000; 1.000000;0.000000;;} |
-- 作者:卷积内核 -- 发布时间:12/15/2008 3:27:00 PM -- 通过前面的介绍,可以建立起一个网格模型,但这个网格模型是浑然一体的,而在现实生活中,为了能独立对一个物体的不同部分进行变换,必须将模型分割成不同的模块,在.x文件中使用框架(frame)对一个网格模型的不同部分进行组织和管理。框架仅仅是一个外壳,在框架中通常需要包含具体的网格和一个框架变换矩阵,其中框架变换矩阵用于指定该框架包含的部分在整个模型中的初始位置。 模板Frame和FrameTransformMatrix的定义如下: Defines a coordinate frame, or "frame of reference." The Frame template is open and can contain any object. The D3DX mesh-loading functions recognize Mesh, FrameTransformMatrix, and Frame template instances as child objects when loading a Frame instance. template Frame{ < 3D82AB46-62DA-11CF-AB39-0020AF71E433 > [...] } Defines a local transform for a frame (and all its child objects). template FrameTransformMatrix{ < F6F23F41-7686-11cf-8F52-0040333594A3 > Matrix4x4 frameMatrix;} frameMatrix - A Matrix4x4 template. template Matrix4x4{ < F6F23F45-7686-11cf-8F52-0040333594A3 > array float matrix[16];} array float matrix[16] - Array of 16 floats. 我们在cube_2.x的基础上添加框架构成cube_3.x: xof 0302txt 0064 |
-- 作者:卷积内核 -- 发布时间:12/15/2008 3:27:00 PM -- 为了使一个.x文件产生动画,必须至少提供一个动画集,每个动画集都应具有一个对某个框架的引用。模板 AnimationSet用来定义动画集: Contains one or more Animation objects. Each animation within an animation set has the same time at any given point. Increasing the animation set's time increases the time for all the animations it contains. template AnimationSet{ < 3D82AB50-62DA-11cf-AB39-0020AF71E433 > [ Animation < 3D82AB4F-62DA-11cf-AB39-0020AF71E433 > ]} [ Animation < 3D82AB4F-62DA-11cf-AB39-0020AF71E433 > ] - Optional animation template. Contains one or more Animation objects. Each animation within an animation set has the same time at any given point. Increasing the animation set's time increases the time for all the animations it contains. template AnimationSet{ < 3D82AB50-62DA-11cf-AB39-0020AF71E433 > [ Animation < 3D82AB4F-62DA-11cf-AB39-0020AF71E433 > ]} [ Animation < 3D82AB4F-62DA-11cf-AB39-0020AF71E433 > ] - Optional animation template. Defines a set of animation keys. A matrix key is useful for sets of animation data that need to be represented as transformation matrices. template AnimationKey{ < 10DD46A8-775B-11CF-8F52-0040333594A3 > DWORD keyType; DWORD nKeys; array TimedFloatKeys keys[nKeys];} keyType - Specifies whether the keys are rotation, scale, position, or matrix keys (using the integers 0, 1, 2, or 4, respectively). 0表示旋转键,在.x文件中,用一个四元数来实现模型的旋转,旋转值使用4个分量w、x、y、z来存储,也就是说,此时变换数组的大小是4,它依次存储四元数的4个分量。 1表示缩放键,可以使用这种类型的关键帧实现模型的缩放,此时变换数组的大小是3,它们分别对应x、y、z轴的缩放值。 2表示平移键,使用3个分量实现模型的平移,此时变换数组的大小是3,它们分别对应沿x、y、z轴的平移值。 4表示变换矩阵键,此时关键帧的变换数组使用16个浮点数来实现该模型的各种变换。因为矩阵可以实现模型的平移、旋转、缩放以及它们的组合变换。 模板AnimationKey用来定义一组动画关键帧,而模板TimeFloatKeys用来定义每个动画关键帧: Defines a set of floats and a positive time used in animations. template TimedFloatKeys { < F406B180-7B3B-11cf-8F52-0040333594A3 > DWORD time; FloatKeys tfkeys; } tfkeys - See FloatKeys. template FloatKeys{ < 10DD46A9-775B-11cf-8F52-0040333594A3 > DWORD nValues; array float values[nValues];} AnimationSet AnimationSet0 { //动画集 Animation Animation0 { //动画 {CubeFrame} //引用上面的立方体框架,表示下面的动画是针对立方体框架的 我们在cube_3.x的基础上添加缩放动画形成cube_5.x: AnimationSet AnimationSet0 { //动画集 Animation Animation0 { //动画 {CubeFrame} // Use the frame containing the cube.
我们也可以在cube_3.x的基础上添加一个沿y轴移动的动画形成cube_6.x: AnimationSet AnimationSet0 { //动画集 Animation Animation0 { //动画 {CubeFrame} // Use the frame containing the cube.
包含在.x文件中的动画通常用来实现模型不同部分之间的相对运动,对于一个模型整体上的运动,应该是在程序中通过其世界变换矩阵来实现。
蒙皮信息 一个动画网格模型很多情况下可能涉及到蒙皮信息,模板XSkinMeshHeader仅对于具有蒙皮信息的网格模型有效,它用来记录网格模型的蒙皮信息,该模板的定义如下: This template is instantiated on a per-mesh basis only in meshes that contain exported skinning information. The purpose of this template is to provide information about the nature of the skinning information that was exported. template XSkinMeshHeader { < 3CF169CE-FF7C-44ab-93C0-F78F62D172E2 > WORD nMaxSkinWeightsPerVertex; WORD nMaxSkinWeightsPerFace; WORD nBones; } nMaxSkinWeightsPerVertex - Maximum number of transforms that affect a vertex in the mesh. This template is instantiated on a per-mesh basis. Within a mesh, a sequence of n instances of this template will appear, where n is the number of bones (X file frames) that influence the vertices in the mesh. Each instance of the template basically defines the influence of a particular bone on the mesh. There is a list of vertex indices, and a corresponding list of weights. template SkinWeights { < 6F0D123B-BAD2-4167-A0D0-80224F25FABB > STRING transformNodeName; DWORD nWeights; array DWORD vertexIndices[nWeights]; array float weights[nWeights]; Matrix4x4 matrixOffset; } The name of the bone whose influence is being defined is transformNodeName, and nWeights is the number of vertices affected by this bone. [B][URL=http://www.cppblog.com/Files/changingnow/CubeResource.rar]下载cube_1.x ~ cube6.x[/URL][/B] |
-- 作者:卷积内核 -- 发布时间:12/15/2008 3:28:00 PM -- Direct3D对加载到内存中的网格模型提供了优化功能,通过网格模型优化可以明显提高三维模型的渲染速度,这对渲染速度要求较高的三维图形程序和游戏具有非常重要的现实意义。 对于程序员而言,对网格模型进行优化是比较简单的,只需调用接口ID3DXMesh的方法Optimize(),该函数的声明如下: Generates a new mesh with reordered faces and vertices to optimize drawing performance. HRESULT Optimize( DWORD Flags, CONST DWORD * pAdjacencyIn, DWORD * pAdjacencyOut, DWORD * pFaceRemap, LPD3DXBUFFER * ppVertexRemap, LPD3DXMESH * ppOptMesh); Remarks This method is very similar to the ID3DXBaseMesh::CloneMesh method, except that it can perform optimization while generating the new clone of the mesh. The output mesh inherits all of the creation parameters of the input mesh. Direct3D提供了7种网格模型优化方式,由枚举常量D3DXMESHOPT定义: Specifies the type of mesh optimization to be performed. typedef enum D3DXMESHOPT{ D3DXMESHOPT_COMPACT = 0x01000000, D3DXMESHOPT_ATTRSORT = 0x02000000, D3DXMESHOPT_VERTEXCACHE = 0x04000000, D3DXMESHOPT_STRIPREORDER = 0x08000000, D3DXMESHOPT_IGNOREVERTS = 0x10000000, D3DXMESHOPT_DONOTSPLIT = 0x20000000, D3DXMESHOPT_DEVICEINDEPENDENT = 0x40000000,} D3DXMESHOPT, *LPD3DXMESHOPT; The D3DXMESHOPT_SHAREVB flag has been removed from this enumeration. Use D3DXMESH_VB_SHARE instead, in D3DXMESH. D3DXMESH typedef enum D3DXMESH{ D3DXMESH_32BIT = 0x001, D3DXMESH_DONOTCLIP = 0x002, D3DXMESH_POINTS = 0x004, D3DXMESH_RTPATCHES = 0x008, D3DXMESH_NPATCHES = 0x4000, D3DXMESH_VB_SYSTEMMEM = 0x010, D3DXMESH_VB_MANAGED = 0x020, D3DXMESH_VB_WRITEONLY = 0x040, D3DXMESH_VB_DYNAMIC = 0x080, D3DXMESH_VB_SOFTWAREPROCESSING = 0x8000, D3DXMESH_IB_SYSTEMMEM = 0x100, D3DXMESH_IB_MANAGED = 0x200, D3DXMESH_IB_WRITEONLY = 0x400, D3DXMESH_IB_DYNAMIC = 0x800, D3DXMESH_IB_SOFTWAREPROCESSING = 0x10000, D3DXMESH_VB_SHARE = 0x1000, D3DXMESH_USEHWONLY = 0x2000, D3DXMESH_SYSTEMMEM = 0x110, D3DXMESH_MANAGED = 0x220, D3DXMESH_WRITEONLY = 0x440, D3DXMESH_DYNAMIC = 0x880, D3DXMESH_SOFTWAREPROCESSING = 0x18000,} D3DXMESH, *LPD3DXMESH; 因为调用ID3DXMesh::Optimize()函数对网格模型进行优化时,需要用到网格模型中每个面的三个邻接信息,该信息在加载网格模型时得到: ID3DXBuffer* material_buffer; DWORD* adj_in = (DWORD*) g_adj_buffer->GetBufferPointer(); // 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) ); |
-- 作者:卷积内核 -- 发布时间:12/15/2008 3:29:00 PM -- 主程序: #pragma warning(disable : 4127 4995) #define IDC_TOGGLE_FULLSCREEN 1 #define OPT_NONE 0 #define release_com(p) do { if(p) { (p)->Release(); (p) = NULL; } } while(0) ID3DXFont* g_font; CDXUTDialogResourceManager g_dlg_resource_manager; ID3DXMesh* g_mesh; ID3DXMesh* g_mesh_attr_sort; //-------------------------------------------------------------------------------------- IDirect3D9* pD3D = DXUTGetD3DObject(); if( FAILED( pD3D->CheckDeviceFormat( pCaps->AdapterOrdinal, pCaps->DeviceType, AdapterFormat, return true; static bool is_first_time = true; if(is_first_time) // if using reference device, then pop a warning message box. return true; //-------------------------------------------------------------------------------------- LPWSTR w_last_back_slash = wcsrchr(wbuf, '\\'); if(w_last_back_slash) V_RETURN(g_dlg_resource_manager.OnCreateDevice(pd3dDevice)); D3DXCreateFont(pd3dDevice, 18, 0, FW_BOLD, 1, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, ID3DXBuffer* material_buffer; V_RETURN(D3DXLoadMeshFromXW(L"Dwarf.x", D3DXMESH_MANAGED, pd3dDevice, &g_adj_buffer, &material_buffer, NULL, D3DXMATERIAL* xmaterials = (D3DXMATERIAL*) material_buffer->GetBufferPointer(); for(DWORD i = 0; i < g_num_materials; i++) WCHAR wfilename[256]; g_mesh_textures[i] = NULL; if(xmaterials[i].pTextureFilename != NULL && lstrlen(wfilename) > 0) lstrcpy(g_opt_info, L"optimize method: none"); DWORD* adj_in = (DWORD*) g_adj_buffer->GetBufferPointer(); V_RETURN(g_mesh->Optimize(D3DXMESHOPT_ATTRSORT | D3DXMESH_MANAGED, adj_in, NULL, NULL, NULL, V_RETURN(g_mesh->Optimize(D3DXMESHOPT_STRIPREORDER | D3DXMESH_MANAGED, adj_in, NULL, NULL, NULL, return S_OK; V_RETURN(g_dlg_resource_manager.OnResetDevice()); // set dialog position and size g_button_dlg.SetLocation(pBackBufferSurfaceDesc->Width - 170, 0); // setup view matrix D3DXMATRIX mat_view; D3DXMatrixLookAtLH(&mat_view, &eye, &at, &up); // set projection matrix pd3dDevice->SetRenderState(D3DRS_AMBIENT, 0xFFFFFFFF); return S_OK; //-------------------------------------------------------------------------------------- release_com(g_text_sprite); delete[] g_mesh_materials; if(g_mesh_textures) delete[] g_mesh_textures; release_com(g_font); //-------------------------------------------------------------------------------------- D3DXMatrixTranslation(&mat_translation, 0, -0.7f, 0); pd3dDevice->SetTransform(D3DTS_WORLD, &mat_world); //-------------------------------------------------------------------------------------- // show frame and device states // show other simple information // show helper information if(g_show_help) text_helper.SetInsertionPos(40, surface_desc->Height - 15 * 3); text_helper.End(); //-------------------------------------------------------------------------------------- if(g_settings_dlg.IsActive()) // Clear the render target and the zbuffer // Render the scene switch(g_render_flag) case OPT_ATTR_SORT: case OPT_STRIP_REORDER: case OPT_VERTEX_CACHE: RenderText(); V(g_button_dlg.OnRender(fElapsedTime)); V( pd3dDevice->EndScene() ); if(g_settings_dlg.IsActive()) *pbNoFurtherProcessing = g_button_dlg.MsgProc(hWnd, uMsg, wParam, lParam); return 0; case 48: // press key "0" case 49: // press key "1" case 50: // press key "2" case 51: // press key "3" //-------------------------------------------------------------------------------------- case IDC_TOGGLE_REF: case IDC_CHANGE_DEVICE: //-------------------------------------------------------------------------------------- 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); //-------------------------------------------------------------------------------------- // Set the callback functions // Initialize DXUT and create the desired Win32 window and Direct3D device for the application // Start the render loop // TODO: Perform any application-level cleanup here return DXUTGetExitCode();
[B][URL=http://www.cppblog.com/Files/changingnow/OptimizedMesh.rar]下载示例工程[/URL][/B] |
-- 作者:秋十三 -- 发布时间:1/2/2009 7:52:00 PM -- 好啊 我喜欢 |
-- 作者:秋十三 -- 发布时间:2/16/2009 1:18:00 PM -- 这么每人顶啊 |
-- 作者:卷积内核 -- 发布时间:2/18/2009 8:25:00 AM --
以为没人喜欢这方面知识,就没有继续发了,如果你喜欢我会继续完善这方面内容。共同学习、共同进步!!~~ |
W 3 C h i n a ( since 2003 ) 旗 下 站 点 苏ICP备05006046号《全国人大常委会关于维护互联网安全的决定》《计算机信息网络国际联网安全保护管理办法》 |
218.750ms |