自制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 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. }

用SharpGL显示3DS模型

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

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

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

    crowbar中第一次申请内存是在生成解析器的时候: /* interface.c */CRB_Interpreter *CRB_create_interpreter(void) { MEM_Stor ...

  2. Spring源码情操陶冶-ComponentScanBeanDefinitionParser文件扫描解析器

    承接前文Spring源码情操陶冶-自定义节点的解析,本文讲述spring通过context:component-scan节点干了什么事 ComponentScanBeanDefinitionParse ...

  3. CSharpGL(5)解析3DS文件并用CSharpGL渲染

    CSharpGL(5)解析3DS文件并用CSharpGL渲染 我曾经写过一个简单的*.3ds文件的解析器,但是只能解析最基本的顶点.索引信息,且此解析器是仿照别人的C++代码改写的,设计的也不好,不方 ...

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

    一.问题描述为支持restful风格请求,并且应对可能上传文件的情况,需要在配置hiddenHttpMethodFilter过滤器之前配置MultipartFilter.目的是让MultipartFi ...

  5. 【swupdate文档 四】SWUpdate:使用默认解析器的语法和标记

    SWUpdate:使用默认解析器的语法和标记 介绍 SWUpdate使用库"libconfig"作为镜像描述的默认解析器. 但是,可以扩展SWUpdate并添加一个自己的解析器, ...

  6. PE解析器的编写(一)——总体说明

    之前自己学习了PE文件的格式,后来自己写了个PE文件的解析器,这段时间工作上刚好要用到它,老板需要能查看某个exe中加载的dll的一个工具,我在使用之前自己写的这个东西的时候,发现很多东西都忘记了,所 ...

  7. Spring源码情操陶冶-AnnotationConfigBeanDefinitionParser注解配置解析器

    本文承接前文Spring源码情操陶冶-自定义节点的解析,分析spring中的context:annotation-config节点如何被解析 源码概览 对BeanDefinitionParser接口的 ...

  8. JAVA与DOM解析器基础 学习笔记

    要求 必备知识 JAVA基础知识.XML基础知识. 开发环境 MyEclipse10 资料下载 源码下载   文件对象模型(Document Object Model,简称DOM),是W3C组织推荐的 ...

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

    原文出处 http://www.ibm.com/developerworks/cn/java/j-lo-springview/ 概述 Spring 3.0 默认包含了多种视图和视图解析器,比如 JSP ...

随机推荐

  1. CSS3动画效果结合JS的轮播

    <style> *{;} #big{ width: 100%; height: 280px; } .carousel-wrapper{ width: 500px; height: 280p ...

  2. oracle 11gr2 官方文档下载

    http://www.oracle.com/technetwork/database/enterprise-edition/documentation/index.html

  3. java四种内部类

    内部类有成员内部类,局部内部类,匿名内部类,静态内部类. 1,成员内部类package innerClass; public class InnerClassTest { String s1=&quo ...

  4. Java LinkedList 源码剖析

    LinkedList同时实现了List接口和Deque接口,也就是说它既可以看作一个顺序容器,又可以看作一个队列(Queue),同时又可以看作一个栈(Stack).这样看来,LinkedList简直就 ...

  5. 用SYS_CONNECT_BY_PATH进行层级查询时的排序问题

    用SYS_CONNECT_BY_PATH进行层级查询时, 对同一级别的节点进行排序,可以加order SIBLINGS by 子句实现 WITH N2 AS( SELECT n.ID, org.&qu ...

  6. ftp 服务器搭建和添加用户和目录

    安装: yum install  -y vsftpd 修改配置: vsftpd.conf 修改:anonymous_enable=YES 改为:anonymous_enable=NO 启动/停止/重启 ...

  7. 浅析JVM内存结构和6大区域(转)举例非常好

    内存作为系统中重要的资源,对于系统稳定运行和高效运行起到了关键的作用,Java和C之类的语言不同,不需要开发人员来分配内存和回收内存,而是由JVM来管理对象内存的分配以及对象内存的回收(又称为垃圾回收 ...

  8. python学习粘贴

    1. Python通过re模块提供对正则表达式的支持.使用re的一般步骤是先使用re.compile()函数,将正则表达式的字符串形式编译为Pattern实例,然后使用Pattern实例处理文本并获得 ...

  9. node的事件模块应用(译)

    第一次接触Node.js时,就觉得他只不过是用javascript实现的服务端.但实际上他提供了许多浏览器端不具备的方法,比如EventEmitter类.我们在本文中来学习如何使用EventEmitt ...

  10. (转)详解Linux Top 命令

    top 命令是最流行的性能监视工具之一,我们必需了解.它是一个优秀的交互式工具,用于监视性能.它提供系统整体性能,但报告进程信息才是 top 命令的长处.top 命令交互界面如下图所视: