自制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个根结点的树状结构。

 MAIN CHUNK 0x4D4D
3D EDITOR CHUNK 0x3D3D
OBJECT BLOCK 0x4000
TRIANGULAR MESH 0x4100
VERTICES LIST 0x4110
FACES DESCRIPTION 0x4120
FACES MATERIAL 0x4130
MAPPING COORDINATES LIST 0x4140
SMOOTHING GROUP LIST 0x4150
LOCAL COORDINATES SYSTEM 0x4160
LIGHT 0x4600
SPOTLIGHT 0x4610
CAMERA 0x4700
MATERIAL BLOCK 0xAFFF
MATERIAL NAME 0xA000
AMBIENT COLOR 0xA010
DIFFUSE COLOR 0xA020
SPECULAR COLOR 0xA030
TEXTURE MAP 0xA200
BUMP MAP 0xA230
REFLECTION MAP 0xA220
[SUB CHUNKS FOR EACH MAP]
MAPPING FILENAME 0xA300
MAPPING PARAMETERS 0xA351
KEYFRAMER CHUNK 0xB000
MESH INFORMATION BLOCK 0xB002
SPOT LIGHT INFORMATION BLOCK 0xB007
FRAMES (START AND END) 0xB008
OBJECT NAME 0xB010
OBJECT PIVOT POINT 0xB013
POSITION TRACK 0xB020
ROTATION TRACK 0xB021
SCALE TRACK 0xB022
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的枚举类型

         enum ChunkType
{
MainChunk = 0x4D4D,
_3DEditorChunk = 0x3D3D,
CVersion = 0x0002,
KeyFramerChunk = 0xB000,
MaterialBlock = 0xAFFF,
MaterialName = 0xA000,
AmbientColor = 0xA010,
DiffuseColor = 0xA020,
SpecularColor = 0xA030,
C_MATSHININESS = 0xA040,
TextureMap = 0xA200,
MappingFilename = 0xA300,
ObjectBlock = 0x4000,
TriangularMesh = 0x4100,
VerticesList = 0x4110,
FacesDescription = 0x4120,
FacesMaterial = 0x4130,
MappingCoordinatesList = 0x4140
}

ChunkType

解析结果

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

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

          foreach (var entity in _3dsFile.Entities)
{
gl.Enable(OpenGL.GL_TEXTURE_2D);
gl.BindTextue(OpenGL.GL_TEXTURE_2D, this.texture.TextureName);
gl.Begin(SharpGL.Enumerations.BeginMode.Triangles);
foreach (var triangle in entity.indices)
{
var point1 = entity.vertices[triangle.vertex1];
var uv1 = entity.texcoords[triangle.vertex1];
gl.TexCoord(uv1.U, uv1.V);
gl.Vertex(point1.X, point1.Y, point1.Z);
var point2 = entity.vertices[triangle.vertex2];
var uv2 = entity.texcoords[triangle.vertex2];
gl.TexCoord(uv2.U, uv2.V);
gl.Vertex(point2.X, point2.Y, point2.Z);
var point3 = entity.vertices[triangle.vertex3];
var uv3 = entity.texcoords[triangle.vertex3];
gl.TexCoord(uv3.U, uv3.V);
gl.Vertex(point3.X, point3.Y, point3.Z);
}
gl.End();
}

用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. 接收新信息,在会话中看不到(thread表数据插入/更新失败)

    分析原因:收到短信,sms表插入信息,触发器会自动更新thread表,更新失败导致一直有一条未读信息数量显示,但在会话列表中却看不到. (偶现,低概率. 解决方法:接收新信息插入后,立即查询threa ...

  2. 结合阿里云服务器,设置家中jetson tk1随时远程登陆

    前提条件: 1.路由配置dmz主机为tk1的ip ,设置路由器中ssh 端口22的访问权限 2.有一台远程服务器,服务器安装了php可以运行php文件(我使用的是阿里云) 家中tk1配置: 脚本pyt ...

  3. jquery easyui window中的datagrid,只能显示一次问题

    最近项目中用到easyui 的动态创建window ,window中嵌入了datagruid.第一次打开是能显示数据,但再次打开时确没显示: 注:url已成功返回了数据. 多次查阅easyui帮助文档 ...

  4. C++回顾map的用法

    map<T, T>是C++的STL中存储key-value键值对数据结构的最基础的模板类,相对于multimap可以重复的key值,map的key是非重复的. C++的reference这 ...

  5. yii隐藏域的使用方法

    <?= $form->field($model, 'time')->textInput()->hiddenInput(['value'=>time()])->lab ...

  6. nginx负载均衡最新

    配置conf文件 #user  nobody;worker_processes  1;#error_log  logs/error.log;#error_log  logs/error.log  no ...

  7. Bootstrap 折叠(Collapse)插件

    折叠(Collapse)插件可以很容易地让页面区域折叠起来.无论您用它来创建折叠导航还是内容面板,它都允许很多内容选项. 如果您想要单独引用该插件的功能,那么您需要引用 collapse.js.同时, ...

  8. java的继承

    1.什么是继承:一个类从另外一个类中得到成员.属性和行为方法等. 案例: //父类 public class Animal { // 变量 public int height=1; // 方法 pub ...

  9. 学习ES6--data2

    变量的解构: let [a, b, c] = [1, 2, 3] 等号左边的值等于等号右边的值,一一对应.假如右边没有相对应的值,如 let [a, b, c] = [1, 2, ] 这时候,c = ...

  10. 在 Mac OS 上使用 TypeScript 编写 ASP.NET Core 1.0 应用

    var appInsights=window.appInsights||function(config){ function r(config){t[config]=function(){var i= ...