自制C#版3DS文件的解析器并用SharpGL显示3DS模型
自制C#版3DS文件的解析器并用SharpGL显示3DS模型
据说*.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文件格式
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块结构
实际上完整的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子块 |
读取的思路是:首先根据偏移量和长度找到一个块的标识符,然后据此来判断它是什么块,遇到我们需要的块,就进一步读取,如果不需要,直接跳过这一块,读取下面的块。
我们的解析器需要顶点、面和贴图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) |
|
FACES DESCRIPTION(面数据在这) |
|
|
Identifier |
0x4120 |
|
Length |
varying + sub-chunks length |
|
Chunk father |
TRIANGULAR MESH |
|
Sub chunks |
FACES |
|
Data |
Polygons number (unsigned short) |
|
MAPPING COORDINATES LIST(贴图数据在这) |
|
|
Identifier |
0x4140 |
|
Length |
varying + sub-chunks length |
|
Chunk father |
TRIANGULAR MESH |
|
Sub chunks |
SMOOTHING |
|
Data |
Vertices number (unsigned short) |
据此给出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
解析结果
解析结果为一个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模型的更多相关文章
- 自制编程语言crowbar(v0.1)构建解析器时分配内存
crowbar中第一次申请内存是在生成解析器的时候: /* interface.c */CRB_Interpreter *CRB_create_interpreter(void) { MEM_Stor ...
- Spring源码情操陶冶-ComponentScanBeanDefinitionParser文件扫描解析器
承接前文Spring源码情操陶冶-自定义节点的解析,本文讲述spring通过context:component-scan节点干了什么事 ComponentScanBeanDefinitionParse ...
- CSharpGL(5)解析3DS文件并用CSharpGL渲染
CSharpGL(5)解析3DS文件并用CSharpGL渲染 我曾经写过一个简单的*.3ds文件的解析器,但是只能解析最基本的顶点.索引信息,且此解析器是仿照别人的C++代码改写的,设计的也不好,不方 ...
- springMVC:为MultipartFilte配置了上传文件解析器,报错或不能使用
一.问题描述为支持restful风格请求,并且应对可能上传文件的情况,需要在配置hiddenHttpMethodFilter过滤器之前配置MultipartFilter.目的是让MultipartFi ...
- 【swupdate文档 四】SWUpdate:使用默认解析器的语法和标记
SWUpdate:使用默认解析器的语法和标记 介绍 SWUpdate使用库"libconfig"作为镜像描述的默认解析器. 但是,可以扩展SWUpdate并添加一个自己的解析器, ...
- PE解析器的编写(一)——总体说明
之前自己学习了PE文件的格式,后来自己写了个PE文件的解析器,这段时间工作上刚好要用到它,老板需要能查看某个exe中加载的dll的一个工具,我在使用之前自己写的这个东西的时候,发现很多东西都忘记了,所 ...
- Spring源码情操陶冶-AnnotationConfigBeanDefinitionParser注解配置解析器
本文承接前文Spring源码情操陶冶-自定义节点的解析,分析spring中的context:annotation-config节点如何被解析 源码概览 对BeanDefinitionParser接口的 ...
- JAVA与DOM解析器基础 学习笔记
要求 必备知识 JAVA基础知识.XML基础知识. 开发环境 MyEclipse10 资料下载 源码下载 文件对象模型(Document Object Model,简称DOM),是W3C组织推荐的 ...
- [转载]开发 Spring 自定义视图和视图解析器
原文出处 http://www.ibm.com/developerworks/cn/java/j-lo-springview/ 概述 Spring 3.0 默认包含了多种视图和视图解析器,比如 JSP ...
随机推荐
- 如何让电脑公司Win7系统自动关闭停止响应的程序
在注册表编辑器窗口左侧,依次展开HKEY_CURRENT_USER\ControlPanel\Desktop,选中Desktop,在右边的窗口中选择AutoEndTasks,双击打开AutoEndTa ...
- Spark中常用工具类Utils的简明介绍
<深入理解Spark:核心思想与源码分析>一书前言的内容请看链接<深入理解SPARK:核心思想与源码分析>一书正式出版上市 <深入理解Spark:核心思想与源码分析> ...
- 关于.NET大数据量大并发量的数据连接池管理
转自:http://www.cnblogs.com/virusswb/archive/2010/01/08/1642055.html 我以前对.NET连接池的认识是错误的,原来以为在web.confi ...
- 一种模拟position: sticky;的方法
直接上代码,本例采用了jQuery来进行介绍 CSS部分: .sticky { position: fixed; top: 0; } JS部分: var stickyBar = $('.sticky- ...
- The Template method pattern
public class TemplateMethodDemo { public static void main(String[] args) { Teacher test=new Javatrea ...
- Spring aop 原始的工作原理的理解
理解完aop的名词解释,继续学习spring aop的工作原理. 首先明确aop到底是什么东西?又如何不违单一原则并实现交叉处理呢? 如果对它的认识只停留在面向切面编程,那就脏了.从oop(Objec ...
- VS非web项目使用Transformation配置文件
Web项目中的Transformation使用起来非常方便,特别是本地与服务器情况不一致时调试下以及webdeploy的配合使用. 步骤: 1. 在项目中新建App.Debug.Config及App. ...
- catalina.properties
追踪 startup.bat set "EXECUTABLE=%CATALINA_HOME%\bin\catalina.bat" call "%EXECUTABLE%&q ...
- CSS伪类选择器
一.CSS伪类选择器用于给某些选择器添加效果语法规则:选择器:伪选择器例:a:link {color: #FF0000} 未访问的链接 a:visited {color: #00FF00} 已访问的链 ...
- uva 11357 Matches
// uva 11357 Matches // // 题目大意: // // 给你n个火柴,用这n个火柴能表示的非负数有多少个,不能含有前导零 // // 解题思路: // // f[i] 表示正好用 ...