自制C#版3DS文件的解析器并用SharpGL显示3DS模型

+BIT祝威+悄悄在此留下版了个权的信息说:

据说*.3ds格式的3D模型文件是很古老和过时的格式。本文参考了(http://www.spacesimulator.net/wiki/index.php?title=Tutorials:3ds_Loader)和(http://www.cnblogs.com/lookof/archive/2009/03/27/1423695.html),在此表示感谢。本文讲解如何从零开始用C#写一个3ds文件的解析器,然后用SharpGL(C#对opengl的封装)来显示3ds模型。有图有真相。

上图使用的3ds模型文件和贴图文件在此。(spaceship.zip)(spaceshiptexture.bmp

3DS文件格式

+BIT祝威+悄悄在此留下版了个权的信息说:

3ds文件是二进制的。3ds格式的基本单元叫块(chunk)。我们就是读这样一块一块的信息。目录树如下,缩进风格体现了块的父子关系。可见3ds模型文件和XML文件类似,都是只有1个根结点的树状结构。

 1 MAIN CHUNK 0x4D4D
 2    3D EDITOR CHUNK 0x3D3D
 3       OBJECT BLOCK 0x4000
 4          TRIANGULAR MESH 0x4100
 5             VERTICES LIST 0x4110
 6             FACES DESCRIPTION 0x4120
 7                FACES MATERIAL 0x4130
 8             MAPPING COORDINATES LIST 0x4140
 9                SMOOTHING GROUP LIST 0x4150
10             LOCAL COORDINATES SYSTEM 0x4160
11          LIGHT 0x4600
12             SPOTLIGHT 0x4610
13          CAMERA 0x4700
14       MATERIAL BLOCK 0xAFFF
15          MATERIAL NAME 0xA000
16          AMBIENT COLOR 0xA010
17          DIFFUSE COLOR 0xA020
18          SPECULAR COLOR 0xA030
19          TEXTURE MAP 1 0xA200
20          BUMP MAP 0xA230
21          REFLECTION MAP 0xA220
22          [SUB CHUNKS FOR EACH MAP]
23             MAPPING FILENAME 0xA300
24             MAPPING PARAMETERS 0xA351
25       KEYFRAMER CHUNK 0xB000
26          MESH INFORMATION BLOCK 0xB002
27          SPOT LIGHT INFORMATION BLOCK 0xB007
28          FRAMES (START AND END) 0xB008
29             OBJECT NAME 0xB010
30             OBJECT PIVOT POINT 0xB013
31             POSITION TRACK 0xB020
32             ROTATION TRACK 0xB021
33             SCALE TRACK 0xB022
34             HIERARCHY POSITION 0xB030

3DS块结构

+BIT祝威+悄悄在此留下版了个权的信息说:

实际上完整的chunk列表有上千种类型,我们只需解析其中的顶点列表、面列表和纹理UV列表就行了。

以类型标识为0x4D4D的MAIN CHUNK为例,整个3ds文件的前两个byte必须是0x4D4D,否则就说明这个文件不是3ds模型文件。然后从第3到第6个byte是一个Uint32型的数值,表示整个MAIN CHUNK的长度。由于MAIN CHUNK是整个3ds文件的根结点,它的长度也即整个3ds文件的长度。

块(Chunk)的结构

每一个“chunk”的结构如下所示:


偏移量


长度


0


2


块标识符


2


4


块长: 块数据 + 子块内容


6


n


块数据


6+n


m


S子块

+BIT祝威+悄悄在此留下版了个权的信息说:

读取的思路是:首先根据偏移量和长度找到一个块的标识符,然后据此来判断它是什么块,遇到我们需要的块,就进一步读取,如果不需要,直接跳过这一块,读取下面的块。

我们的解析器需要顶点、面和贴图UV信息,根据3ds模型文件的树状结构,可以找到需要解析的Chunk如下。


MAIN CHUNK


Identifier


0x4d4d


Length


0 + sub-chunks length


Chunk father


None


Sub chunks


3D EDITOR CHUNK


Data


None


3D EDITOR CHUNK


Identifier


0x3D3D


Length


0 + sub-chunks length


Chunk father


MAIN CHUNK


Sub chunks


OBJECT BLOCK, MATERIAL BLOCK, KEYFRAMER CHUNK


Data


None


OBJECT BLOCK


Identifier


0x4000


Length


Object name length + sub-chunks length


Chunk father


3D EDITOR CHUNK


Sub chunks


TRIANGULAR MESH, LIGHT, CAMERA


Data


Object name


TRIANGULAR MESH


Identifier


0x4100


Length


0 + sub-chunks length


Chunk father


OBJECT BLOCK


Sub chunks


VERTICES LIST, FACES DESCRIPTION, MAPPING COORDINATES LIST


Data


None


VERTICES LIST(点数据在这)


Identifier


0x4110


Length


varying + sub-chunks length


Chunk father


TRIANGULAR MESH


Sub chunks


None


Data


Vertices number (unsigned short)
Vertices list: x1,y1,z1,x2,y2,z2 etc. (for each vertex: 3*float)


FACES DESCRIPTION(面数据在这)


Identifier


0x4120


Length


varying + sub-chunks length


Chunk father


TRIANGULAR MESH


Sub chunks


FACES
MATERIAL


Data


Polygons number (unsigned short)
Polygons list: a1,b1,c1,a2,b2,c2 etc. (for each point: 3*unsigned short)
Face flag: face options, sides visibility etc. (unsigned short)


MAPPING COORDINATES LIST(贴图数据在这)


Identifier


0x4140


Length


varying + sub-chunks length


Chunk father


TRIANGULAR MESH


Sub chunks


SMOOTHING
GROUP LIST


Data


Vertices number (unsigned short)
Mapping coordinates list: u1,v1,u2,v2 etc. (for each vertex: 2*float)

据此给出Chunk的枚举类型

 1         enum ChunkType
 2         {
 3             MainChunk = 0x4D4D,
 4             _3DEditorChunk = 0x3D3D,
 5             CVersion = 0x0002,
 6             KeyFramerChunk = 0xB000,
 7             MaterialBlock = 0xAFFF,
 8             MaterialName = 0xA000,
 9             AmbientColor = 0xA010,
10             DiffuseColor = 0xA020,
11             SpecularColor = 0xA030,
12             C_MATSHININESS = 0xA040,
13             TextureMap = 0xA200,
14             MappingFilename = 0xA300,
15             ObjectBlock = 0x4000,
16             TriangularMesh = 0x4100,
17             VerticesList = 0x4110,
18             FacesDescription = 0x4120,
19             FacesMaterial = 0x4130,
20             MappingCoordinatesList = 0x4140
21         }

ChunkType

解析结果

+BIT祝威+悄悄在此留下版了个权的信息说:

解析结果为一个3dsFile类型的实例,它包含若干模型(称为entity)。每个entity都含有描述三维模型的顶点、面和贴图UV信息,据此我们用SharpGL来将其显示出来。

 1          foreach (var entity in _3dsFile.Entities)
 2          {
 3                    gl.Enable(OpenGL.GL_TEXTURE_2D);
 4                    gl.BindTextue(OpenGL.GL_TEXTURE_2D, this.texture.TextureName);
 5                    gl.Begin(SharpGL.Enumerations.BeginMode.Triangles);
 6                    foreach (var triangle in entity.indices)
 7                    {
 8                             var point1 = entity.vertices[triangle.vertex1];
 9                             var uv1 = entity.texcoords[triangle.vertex1];
10                             gl.TexCoord(uv1.U, uv1.V);
11                             gl.Vertex(point1.X, point1.Y, point1.Z);
12                             var point2 = entity.vertices[triangle.vertex2];
13                             var uv2 = entity.texcoords[triangle.vertex2];
14                             gl.TexCoord(uv2.U, uv2.V);
15                             gl.Vertex(point2.X, point2.Y, point2.Z);
16                             var point3 = entity.vertices[triangle.vertex3];
17                             var uv3 = entity.texcoords[triangle.vertex3];
18                             gl.TexCoord(uv3.U, uv3.V);
19                             gl.Vertex(point3.X, point3.Y, point3.Z);
20                    }
21                    gl.End();
22          }
23
24  

用SharpGL显示3DS模型

需要注意的一点是,SharpGL加载的贴图是上下反向的,所以你必须把准备好的贴图上下翻转,才能在SharpGL里正常使用。

+BIT祝威+悄悄在此留下版了个权的信息说:

说起来容易做起来难,需要源码的同学麻烦支持一下,用本文下方的捐款二维码(也可在此找到)向我捐款100元并留下你的ID、Email等联系方式。您也可以在公告栏找到我的联系方式,任何不直接索要源码的交流都是欢迎的!

时间: 2024-10-22 21:58:19

自制C#版3DS文件的解析器并用SharpGL显示3DS模型的相关文章

自制编程语言crowbar(v0.1)构建解析器时分配内存

crowbar中第一次申请内存是在生成解析器的时候: /* interface.c */CRB_Interpreter *CRB_create_interpreter(void) { MEM_Storage storage; CRB_Interpreter *interpreter; storage = MEM_open_storage(0); interpreter = MEM_storage_malloc(storage, sizeof(struct CRB_Interpreter_tag)

springMVC:为MultipartFilte配置了上传文件解析器,报错或不能使用

一.问题描述为支持restful风格请求,并且应对可能上传文件的情况,需要在配置hiddenHttpMethodFilter过滤器之前配置MultipartFilter.目的是让MultipartFilter过滤器先将带文件上传的请求,进行解析.以便hiddenHttpMethodFilter可以取到”_method”参数,转化为相应的http动作. 既然multipartFilter要进行上传文件的解析,那么必然需要MutipartResolver,那么问题发生了! 二.报错:Unable t

Android解析XML之SAX解析器

SAX(Simple API for XML)解析器是一种基于事件的解析器,它的核心是事件处理模式,主要是围绕着事件源以及事件处理器来工作的.当事件源产生事件后,调用事件处理器相应的处理方法,一个事件就可以得到处理.在事件源调用事件处理器中特定方法的时候,还要传递给事件处理器相应事件的状态信息,这样事件处理器才能够根据提供的事件信息来决定自己的行为. SAX解析器的优点是解析速度快,占用内存少.非常适合在Android移动设备中使用. SAX相关类及API DefaultHandler:是一个事

C语言实现的lisp解析器介绍

近期.由于Perl而学习函数式编程, 再进一步学习lisp, 真是一学习就发现自己的渺小. 无意中找到了一个很easy的C语言版的, lisp解析器. 代码非常短, 却非常见功底, 涨姿势了. 附带还学习了垃圾回收, 真是收获不少! http://piumarta.com/software/lysp/ 但愿局域网能訪问.

[转载]开发 Spring 自定义视图和视图解析器

原文出处 http://www.ibm.com/developerworks/cn/java/j-lo-springview/ 概述 Spring 3.0 默认包含了多种视图和视图解析器,比如 JSP.Velocity 视图等,但在某些情况下,我们需要开发自定义的视图及其解析器,以便显示特殊文件格式的视图,我们也可以使用自定义视图及解析器,针对特定的视图做相应的处理.本文将通过一个示例来介绍如何开发 Spring 自定义视图和视图解析器,来显示后缀名为 SWF 的视图,并提供一个简单的注册机制,

Atitit。Tree文件解析器的原理流程与设计实现  java  c# php js

Atitit.Tree文件解析器的原理流程与设计实现  java  c# php js 1. 解析原理与流程1 1.1. 判断目录  ,表示服  dirFlagChar = "└├─";1 1.2. 剑豪制表符出现的位置与文件夹级别对应表1 1.3. 主要判读流程2 2. Tree结果2 3. Code----3 4. 结果5 1. 解析原理与流程 1.1. 判断目录  ,表示服  dirFlagChar = "└├─"; 其中-类似于剑豪的制表符是表示目录的..够

安卓使用pull解析器解析XML文件

学习一下: 1 public class MainActivity extends Activity { 2 3 List<City> cityList; 4 @Override 5 protected void onCreate(Bundle savedInstanceState) { 6 super.onCreate(savedInstanceState); 7 setContentView(R.layout.activity_main); 8 } 9 10 public void cli

【Android进阶】解析XML文件之使用DOM解析器

在前面的文章中,介绍了使用SAX解析器对XML文件进行解析,SAX解析器的优点就是占用内存小.这篇文章主要介绍使用DOM解析器对XML文件进行解析.DOM解析器的优点可能是理解起来比较的直观,当然,每个人对不同的解析方法可能有不同的喜好.但是DOM解析器有个比较大的缺点,就是占用内存比较多,在Android中的XML解析中,还是更推荐其他的解析方式. 下面介绍使用DOM解析器对XML进行解析. 下面是我们需要解析的xml文件 <?xml version="1.0" encodin

javap -- Java 类文件解析器

参考文档 http://blog.chinaunix.net/uid-692788-id-2681132.html http://docs.oracle.com/javase/7/docs/technotes/tools/solaris/javap.html 功能说明:Java 类文件解析器. 语法:javap [ 命令选项 ] class. . . 补充说明: javap 命令用于解析类文件.其输出取决于所用的选项.若没有使用选项,javap 将输出传递给它的类的 public 域及方法.ja