Wings 3D/用户手册/Wings 文件格式
查看 http://wings3d.com/ 获取用 Erlang 编写的开源建模器。
需要查看的重要源文件:.../src/wings.hrl 和 .../src/wings_ff_wings.erl。
另一个参考是 用 Perl 实现的导出器,它已过时。
请注意,Wings 目前正在开发中,包括文件格式的更改,因此建议暂停此文档的工作,直到文件格式再次稳定。
一个 *.wings 文件包含 3 个主要部分
- 1. 头部
- 头部长度为 15 字节,本质上是 ASCII,由人类可读的字符串 "#!WINGS-1.0" 以及十六进制字节 0x0D、0x0A、0x1A、0x04 组成,即 "\r\n^Z^D",即 CR、LF、SUB 和 EOT(Ctrl-Z 在 Windows 中是“输入结束”字符,Ctrl-D 在 UNIX 中也是如此)。
- 2. 数据长度
- 一个 4 字节无符号整数,以大端格式存储整个文件的大小。此值应与磁盘上的文件大小匹配,否则文件丢失数据。
- 3. 数据
- 文件主体,以 Erlang 的 外部项格式 存储,如第 8.1 节所示;具体来说,它是一个Zlib 压缩的项,由前两个字节 131、80 指示。接下来的 4 个字节是一个无符号整数,表示未压缩数据的长度。文件的其余部分是实际的压缩数据/项。
- 当使用 Erlang 或具有完整接口的语言处理 *.wings 文件时(在 Erlang 分发版中存在一个 C 接口 和一个 Java 接口,还有 Python 接口 在其他地方),只需将整个数据部分馈送到相应的函数/方法即可。
- 但是,当在其他语言中处理 *.wings 文件时,这 6 个字节可能被视为额外的头部信息,其余部分必须解压缩,然后进一步处理以重建项的嵌套结构。
为了了解简单的 Wings 模型在 Erlang 语法中如何呈现(在解压缩后;手动缩进和添加注释/链接以强调结构并提供帮助)

{ wings, 2, % The Topmost Tuple
{
[ % Shapes
{ object, "tetrahedron1",
{ winged,
[
[
{ color_rt, <<0,0,0,0,0,0,0,0,63,128,0,0>> },
{ color_lt, <<63,128,0,0,0,0,0,0,0,0,0,0>> },
{ edge, 0,1,2,0,4,2,1,3 }
],
[
{ color_rt, <<0,0,0,0,63,128,0,0,0,0,0,0>> },
{ color_lt, <<0,0,0,0,0,0,0,0,63,128,0,0>> },
{ edge, 0,2,0,3,3,0,2,5 }
],
[
{ color_rt, <<63,128,0,0,0,0,0,0,0,0,0,0>> },
{ color_lt, <<0,0,0,0,63,128,0,0,0,0,0,0>> },
{ edge, 0,3,3,2,5,1,0,4 }
],
[
{ color_rt, <<0,0,0,0,0,0,0,0,63,128,0,0>> },
{ edge, 1,2,1,0,5,4,0,1 }
],
[
{ color_lt, <<63,128,0,0,0,0,0,0,0,0,0,...>> },
{ edge, 1,3,2,1,2,0,3,5 }
],
[
{ color_rt, <<0,0,0,0,63,128,0,0,0,0,...>> },
{ edge, 2,3,1,3,4,3,1,2 }
]
],
[ [], [], [], [] ],
[
[ <<0,0,0,0,0,0,0,0,63,241,107,40,245,93,114,...>> ],
[ <<0,0,0,0,0,0,0,0,191,225,107,40,245,93,...>> ],
[ <<191,240,0,0,0,0,0,0,191,225,107,40,245,...>> ],
[ <<63,240,0,0,0,0,0,0,191,225,107,40,...>> ]
],
[]
},
[
{ plugin_states, [] },
{ mode, vertex}
]
}
], % Shapes end
[ % Materials
{ default,
[
{ maps, [] },
{ opengl,
[
{ ambient, { 1.0,1.0,1.0,1.0 } },
{ diffuse, { 1.0,1.0,1.0,1.0 } },
{ emission, { 0.0,0.0,0.0,0.0 } },
{ shininess, 1.0 },
{ specular, { 1.0,1.0,1.0,1.0 } }
]
}
]
}
], % Materials end
[ % Props
{ scene_prefs, [] },
{ plugin_states, [] }
] % Props end
}
}
您将发现两个基本的复合 Erlang 数据类型元组(用大括号表示,如 {something,someother,somemore})和列表(用方括号表示 [elem1,elem2,...], 还有原子(在本示例中不带引号的所有小写字符串,例如 wings、edge、plugin_states)、一个字符串("tetrahedron1")、一些二进制数据(用双尖括号表示,尖括号之间是字节值,如 <<0,1,2,3>>)以及一些整数和浮点数。您会看到,这些都是高度嵌套的(例如,一个列表包含列表,列表包含元组)。
当您无法使用现有的接口(或想要编写新的接口)时,您需要了解 Erlang 项的外部格式,该格式在 这里有很好的说明。请注意,您需要处理字节流并以某种方式自行重建嵌套结构。作为参考,Erlang/OTP 源代码有一个名为“jinterface”的模块,它提供了一组类来实现 Java 中的读取此格式的功能。
要处理 *.wings 文件,您至少应该准备处理以下内容
- 8.4 SMALL_INTEGER_EXT
- 8.5 INTEGER_EXT
- 8.6 FLOAT_EXT
- 8.7 ATOM_EXT
- 8.11 SMALL_TUPLE_EXT
- 8.13 NIL_EXT
- 8.14 STRING_EXT
- 8.15 LIST_EXT
- 8.16 BINARY_EXT
扩展后的最顶层数据结构是一个带标签的元组,包含 3 个元素
符合规范的加载器应该检查前 2 个元素的存在,并验证第 3 个元素是一个 3 元组。
形状部分包含一个列表,每个列表包含一个四元组(4 元组),用于描述每个独立的对象。对象四元组具有以下格式
- 标签原子 'object'。
- 一个包含对象名称的字符串,例如 "tetrahedron1"
- 另一个包含对象实际数据的四元组,由原子 'winged'(如带翼边数据结构)标记。此元组将在下一节中介绍。
- 一个列表,包含有关此对象的插件状态和选择模式的信息。通常,这在导入器/导出器中不会使用。
Wings3D 使用 带翼边数据结构,使其在涉及邻域操作(例如边循环)的所有操作中速度都非常快。*.wings 文件格式直接存储这些带翼边数据结构,因此大部分数据存储在边本身中,而不是在表中(如 *.3ds 或 *.X 文件格式)。
带标签的元组 'winged' 包含定义对象几何形状所需的所有数据。它采用以下格式
- 原子 'winged'(标签)
- 一个列表,包含一系列列表,每个列表定义一条边。
- 一个列表,包含一系列列表,每个列表定义面与材质之间的映射关系。
- 一个列表,包含一系列列表,每个列表定义一个顶点。
- 一个列表,目前用途未知 - 在示例中为 nil。
在第一个列表(边数据)中,找到一系列列表,每个列表定义一条边。在每个边的列表中,可能会出现以下元组。请注意,一个元组在每个边的列表中最多只能出现一次,否则 Wings 将无法加载它,并且它们的出现顺序无关紧要。
- 带标签的 9 元组 'edge':定义带翼边数据结构,必须存在。格式如下
- 原子 'edge'(标签)
- 起始顶点
- 结束顶点
- 左侧面
- 右侧面
- 左侧前驱
- 左侧后继
- 右侧前驱
- 右侧后继
- 带标签的 2 元组 'color_rt':定义右侧顶点边颜色。格式如下
- 原子 'color_rt'(标签)
- 12 字节二进制块,表示 RGB 表示法中的颜色值。每个分量都存储为 32 位单精度浮点数。
- 带标签的 2 元组 'color_lt':定义左侧顶点边颜色。格式如下
- 原子 'color_lt'(标签)
- 12 字节二进制块,表示 RGB 表示法中的颜色值。每个分量都存储为 32 位单精度浮点数。
- 带标签的 2 元组 'uv_rt':定义右侧顶点 UV 坐标。格式如下
- 原子 'uv_rt'(标签)
- 16 字节二进制块,表示 UV 坐标,每个数字使用 8 字节浮点数。
- 带标签的 2 元组 'uv_lt':定义左侧顶点 UV 坐标。格式如下
- 原子 'uv_lt'(标签)
- 16 字节二进制块,表示 UV 坐标,每个数字使用 8 字节浮点数。
从 Wings 1.1.15 开始,此列表中可能包含 UV 和顶点颜色。之前,只能找到其中之一。
在第二个列表(材质数据)中,为由之前读取的带翼边结构定义的每个面提供一个条目。
- 如果面没有材质(默认材质),则列表中的项为 nil。
- 如果面有材质,则条目是一个列表,其中包含一个带标签的 2 元组,格式如下
- 原子 'material'(标签)
- 材质名称的原子,例如 'tetrahedron1_auv'。这是对材质部分的引用。
示例材质结构
[
[
"Cylinder1_auv",
[
[
"maps",
[
[
"diffuse",
3
]
]
],
[
"opengl",
[
[
"ambient",
[
1,1,1,1
]
],
[
"diffuse",
[
1,1,1,1
]
],
[
"emission",
[
0,0,0,0
]
],
[
"shininess",
1
],
[
"specular",
[
1,1,1,1
]
],
[
"vertex_colors",
"ignore"
]
]
]
]
],
[
"default",
[
[
"maps"
],
[
"opengl",
[
[
"ambient",
[
0.789853807692308,0.813333333333333,0.694044444444444,1
]
],
[
"diffuse",
[
0.789853807692308,0.813333333333333,0.694044444444444,1
]
],
[
"emission",
[
0,0,0,1
]
],
[
"shininess",
0
],
[
"specular",
[
0,0,0,1
]
],
[
"vertex_colors",
"set"
]
]
]
]
]
]
示例道具数据
[
[
"scene_prefs"
],
[
"plugin_states",
[
[
"wings_shape",
[
"no_folder",
[
[
"no_folder",
[
"open",
[
1,
[
1,"nil","nil"
]
]
]
]
]
]
]
]
],
[
"current_view",
0
],
[
"views",
[
[
"view",
[
[
"name",
"current_view"
],
[
"aim",
[
0,0,0
]
],
[
"distance_to_aim",
3.14266478310898
],
[
"azimuth",
-284.25
],
[
"elevation",
78.5
],
[
"tracking",
[
0,0
]
],
[
"fov",
45
],
[
"hither",
0.1
],
[
"yon",
10000
]
]
]
]
],
[
"images",
[
[
3,
[
[
"name",
"auvBG"
],
[
"width",
256
],
[
"height",
256
],
[
"samples_per_pixel",
3
],
[
"mask_size",
0
],
[
"pixels",
/* BinaryNode of 196608 bytes. */
]
]
]
]
]
]