自制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 ...
随机推荐
- JSP/Servlet相关
1 简介 JSP(Java Server Page)和Servlet是JavaEE规范的两个基本成员,是JavaWeb开发的重点. JSP的本质是Servlet,当用户向指定的Servlet发送请求时 ...
- hadoop搭建初步总结
1.安装JDK1.1上传运用软件FileZilla,将windows上的jdk压缩包放到linux的root目录下 1.2解压jdk #创建文件夹 mkdir /usr/java(不要挂在在" ...
- maven nexus私服搭建,特别痛苦!!
一.下载nexu,配置环境 参考我的文章:http://www.cnblogs.com/quanyongan/archive/2013/04/24/3037589.html 二.解压并准备Nexus安 ...
- wap,h5页面
网址: 1:天猫(http://m.tmall.com) 2:淘宝(http://m.taobao.com) 3:京东(http://m.jd.com) 4:网易(http://3g.163.com) ...
- sky简介
sky简介 sky是一种构建高性能.跨平台手机APP的新的途径.更值得关注的是,sky是一种渲染引擎.脚本引擎.一个框架和一系列的材料设计模式的窗体组件.sky是当前以及未来手机APP的一种优化手段. ...
- win10 上运行 curl_init() 函数一直报错的解决办法
[问题现象] 1.把 APACHE 的 ZIP 包解压到目录,比如 d:\apache24\ 2.把 PHP 的 ZIP 包解压到目录,比如:d:\php56\ apache 与 php 与 MySQ ...
- 网页的Width ,Height
Jquery中可直接用接口$().height(); 获取浏览器窗口高$(window).height() 获取内部文档高$("body").height() 原生JS 网页可见区 ...
- 深度解析Java8 – AbstractQueuedSynchronizer的实现分析(上)
本文首发在infoQ :www.infoq.com/cn/articles/jdk1.8-abstractqueuedsynchronizer 前言: Java中的FutureTask作为可异步执行任 ...
- NY 325 zb的生日
假设所有西瓜重 Asum,所求的是用 Asum / 2 的背包装,最多装下多少. 刚开始用贪心作的,WA.后来用01背包,结果TLE,数据太大.原来用的是深搜! dfs(int sum, int i) ...
- Activity劫持实例与防护手段
原文地址:Activity劫持实例与防护手段 作者:cjxqhhh (本文只用于学习技术,提高大家警觉,切勿用于非法用途!) 什么叫Activity劫持 这里举一个例子.用户打开安卓手机上的某 ...