The most interesting part of this file is, evidently, the Scene. Opening it up in the chunk parser, it begins like follows, and goes on for a few ten thousands of lines:

0 0x2012: (StorageContainer) [452] {
0 0x0000: (StorageContainer) [6] {
0 0x000b: (StorageRaw) {
Size: 24
String: <).Z..B0`......!........
Hex: 3c 29 06 5a 1e 0c 42 30 60 11 00 00 00 00 00 21 e0 2e 04 00 01 00 00 00 }
1 0x000e: (StorageRaw) {
Size: 19
String: ..............@....
Hex: 00 00 04 00 00 00 00 00 82 00 00 00 00 00 40 00 00 00 00 }
2 0x000e: (StorageRaw) {
Size: 19
String: ..............@....
Hex: 01 00 01 00 00 00 00 00 82 00 00 00 00 00 40 00 00 00 00 }

Inside the Scene stream, we can find a single chunk container. In this case the id of this chunk is 0x2012, and is apparently related to which version, 2010, the file was saved with. This container contains a large number of objects, 452 in this case, with ids that are all very low in value. So, we go look for something we recognize.

While scrolling through the file, I found a short string that I recognized, "no fx", which is part of the NeL node properties plugin. It appears in the file under the following section:

        389 0x001a: (StorageContainer) [25] {
0 0x2150: (StorageContainer) [84] {
0 0x0100: (StorageRaw) {
Size: 4
String: S...
Hex: 53 00 00 00
Int: 83
Float: 1.16308e-43 }
...
18 0x0110: (StorageContainer) [2] {
0 0x0120: (StorageRaw) {
Size: 20
String: XH...u.. ....'......
Hex: 58 48 d6 04 1d 75 d1 16 20 10 00 00 2e 27 0c 05 09 00 00 00 }
1 0x0130: (StorageRaw) {
Size: 9
String: no sound. } }
19 0x0110: (StorageContainer) [2] {
0 0x0120: (StorageRaw) {
Size: 20
String: XH...u.. .../'......
Hex: 58 48 d6 04 1d 75 d1 16 20 10 00 00 2f 27 0c 05 06 00 00 00 }
1 0x0130: (StorageRaw) {
Size: 6
String: no fx. } }
20 0x0110: (StorageContainer) [2] {
0 0x0120: (StorageRaw) {
Size: 20
String: XH...u.. ...........
Hex: 58 48 d6 04 1d 75 d1 16 20 10 00 00 b2 07 00 00 01 00 00 00 }
1 0x0130: (StorageRaw) {
Size: 1
String: .
Hex: 00 } }
...

The 0x2150 chunk seems to exclusively contain 0x0110 entries, preceeded one 0x0100 header entry stating the number of 0x0110 entries. Every entry has a 0x0130 binary blob which is the value of some property, and a 0x0120 binary blob which would likely be some sort of identifier header of this value. Now we should find out how our own nel plugin code puts this value in there, to see if we can make sense of this header.

CExportNel::getScriptAppData(pNode, NEL3D_APPDATA_ENV_FX, "no fx");

This is the line of code that reads the environment fx property from a node. The value of NEL3D_APPDATA_ENV_FX is defined as:

#define NEL3D_APPDATA_ENV_FX (84682543)

Which should appear as 2f 27 0c 05 in the hex output. And it can indeed be found at byte index 12, followed by another integer 6 which happens to match with the length of the value in the value chunk. There's that redundancy showing up again. Looking deeper into the function to figure out the rest of the bytes, we can find this in the getScriptAppData function

AppDataChunk *ap=node->GetAppDataChunk (MAXSCRIPT_UTILITY_CLASS_ID, UTILITY_CLASS_ID, id);

Where the class id MAXSCRIPT_UTILITY_CLASS_ID matches with the first 8 bytes of the header, and the super class id UTILITY_CLASS_ID matches with the following 4 bytes. In short:

58 48 d6 04 1d 75 d1 16 // MAXSCRIPT_UTILITY_CLASS_ID
20 10 00 00 // UTILITY_CLASS_ID
2f 27 0c 05 // NEL3D_APPDATA_ENV_FX
06 00 00 00 // SIZE

We can now be quite sure that the 0x2150 block contains all of the AppData entries. According to the public SDK documentation, the AppData functionality is part of the Animatable base class. Which means that the chunk which contains this block is either an instance of this Animatable class, or more likely a subclass of it. It is of course very likely that the class is somehow identified by the chunk id, which in this case is 0x001a, or 26 in decimal.

Now, the reason why you shouldn't have skipped part 1 and part 2 of this series, is because the data in the DllDirectory and ClassDirectory3 streams is needed to make sense of the Scene stream. Similar to how the ClassDirectory3 references a dll in the DllDirectory by index, the Scene is here referencing a class by index in the ClassDirectory3. This allows to get hold of the ClassId, needed to instantiate the class from the associated class description instance, or to provide a fallback mechanism when the class is part of a missing plugin, and be able to provide the user with the name and description of what is missing from his installation.

At index 26 of the ClassDirectory3 in this file, I can find the following entry:

Entries[26]: (ClassEntry) [2] PARSED {
Header: (ClassEntryHeader) {
DllIndex: -1
ClassId: (0x00000001, 0x00000000)
SuperClassId: 1 }
Name: Node}

Which is the builtin class Node, which probably implements the INode interface that ends up deriving from the Animatable base class.

To confirm this theory, I go the other way, and look for a class I know about.

Entries[13]: (ClassEntry) [2] PARSED {
Header: (ClassEntryHeader) {
DllIndex: -2
ClassId: (0x64c75fec, 0x222b9eb9)
SuperClassId: 3072 }
Name: NeL Material}

At index 13 I find the NeL material script class, which would then be found as a chunk in the file with id 0x000d. And there exists one.

        134 0x000d: (StorageContainer) [8] {
0 0x2034: (StorageRaw) {
Size: 40
String: |.......~...............................
Hex: 7c 00 00 00 7d 00 00 00 7e 00 00 00 7f 00 00 00 80 00 00 00 81 00 00 00 82 00 00 00 83 00 00 00 84 00 00 00 85 00 00 00 }
1 0x204b: (StorageRaw) {
Size: 1
String: .
Hex: 2e }
2 0x21b0: (StorageContainer) [1] {
0 0x1020: (StorageRaw) {
Size: 4
String: ^...
Hex: 5e 00 00 00
Int: 94
Float: 1.31722e-43 } }
3 0x0010: (StorageRaw) {
Size: 8
String: ........
Hex: 0e 00 00 00 09 00 00 00 }
4 0x4001: (StorageRaw) {
Size: 50
String: M.T.R.L._.G.E._.A.c.c._.M.i.k.o.t.o.B.a.n.i.e.r.e. }
5 0x4003: (StorageRaw) {
Size: 4
String: ....
Hex: 0a 02 00 00
Int: 522
Float: 7.31478e-43 }
6 0x4020: (StorageRaw) {
Size: 4
String: ....
Hex: 00 00 00 00
Int: 0
Float: 0 }
7 0x4030: (StorageRaw) {
Size: 16
String: ...............?
Hex: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 80 3f } }

Which, as entry 0x4001 helpfully lets us know by the UTF-16 name MTRL_GE_Acc_MikotoBaniere, is indeed a NeL Material.

So, using this knowledge, we can parse the scene container in a smarter way. Here I provide for you the output at this point.

http://dl.kaetemi.be/blog/maxfile_dump_4.txt

Now that we have figured out which chunks are contained in the Scene streams, and we know how and where some of the data inside it is formatted, how does it all link together? That will be the next subject.

【转】http://blog.kaetemi.be/post/2012/08/20/3ds-Max-File-Format-%28Part-4%29

3ds Max File Format (Part 4: The first useful data; Scene, AppData, Animatable)的更多相关文章

  1. 3ds Max File Format (Part 1: The outer file format; OLE2)

    The 3ds Max file format, not too much documentation to be found about it. There are some hints here ...

  2. 3ds Max File Format (Part 5: How it all links together; ReferenceMaker, INode)

    At this point, you should start to familiarize yourself a bit with the publicly available 3ds Max AP ...

  3. 3ds Max File Format (Part 3: The department of redundancy department; Config)

    Now we'll have a look at the Config stream. It begins like follows, and goes on forever with various ...

  4. 3ds Max File Format (Part 2: The first inner structures; DllDirectory, ClassDirectory3)

    Now that we understand the outer structure of the file, it's time to look closer to what's inside. T ...

  5. 3ds Max File Format (Part 6: We get signal)

    Let's see what we can do now. INode *node = scene.container()->scene()->rootNode()->find(uc ...

  6. AVEVA PDMS to 3ds Max - RvmTranslator6.0beta

    AVEVA PDMS to 3ds Max - RvmTranslator6.0beta eryar@163.com RvmTranslato6.0 translate PDMS RVM to 3ds ...

  7. VRay 2.0 SP1 2.10.01 for 3ds max 9/2008/2009/2010/2011/2012 32/64位 顶渲简体中文版+英文版[中国室内设计论坛-室内人]

    VRay 2.0 SP1 2.10.01 for 3ds max 9/2008/2009/2010/2011/2012 32/64位 顶渲简体中文版+英文版[中国室内设计论坛-室内人] 对最新版本的V ...

  8. 万圣节福利:红孩儿3D引擎开发课程《3ds max导出插件初步》

    ds max文件夹,插件文件夹以及3ds max的可执行程序文件夹: 位的,这里要改成x64,否则启动程序后3ds max会提示"不是有效的win32程序"之类的对话框. 然后要将 ...

  9. 【Unity】3.3 用3ds Max 2015制作模型并将其导入到Unity

    分类:Unity.C#.VS2015 创建日期:2016-04-05 一.常用三维软件简介 由于游戏引擎本身的建模功能相对较弱,无论是专业性还是自由度都无法同专业的三维软件相比,所以大多数游戏中的模型 ...

随机推荐

  1. OSI七层协议大白话解读

    参考链接:https://www.cnblogs.com/zx125/p/11295985.html 国际标准化组织(ISO)制定了osi七层模型,iso规定了各种各样的协议,并且分了7层 应用层 应 ...

  2. 两行配置完全解放gradle编译慢问题

    Android Studio编译经常出现gradle编译缓慢甚至超时问题,抛开电脑硬件配置不说,主要问题还是国内网络环境的因素影响,可以通过修改项目根目录下的build.gradle文件如下: bui ...

  3. python3-cookbook笔记:第四章 迭代器与生成器

    python3-cookbook中每个小节以问题.解决方案和讨论三个部分探讨了Python3在某类问题中的最优解决方式,或者说是探讨Python3本身的数据结构.函数.类等特性在某类问题上如何更好地使 ...

  4. Android实战项目——家庭记账本设计思路

    经过三周左右的Android学习,实感只有上手开发才能有所提高.在此打算做一个家庭记账APP,同时巩固一下学到的东西并且弥补漏洞. 概述 记账是自古以来人类必不可少的一件事,从古代的算盘,到手写账本, ...

  5. c#FTP基本使用

    public class FtpHelper { //基本设置 private static string ftppath = @"ftp://" + "192.168. ...

  6. mysql 表分区操作

    //不支持动态创建分区CREATE TABLE `rpt_exp_event_bucket_creative_d_across` ( `bucket_id` VARCHAR(200) NOT NULL ...

  7. mysql查询中字符串转换成数字

    在操作mysql时,经常需要将字符转换成数字,这一步虽然简单,但不常用的话也很容易忘记,现将在网上找到的方法记录如下: 1.将字符的数字转成数字,比如'0'转成0可以直接用加法来实现例如:将pony表 ...

  8. [SDOI2009]晨跑[最小费用最大流]

    [SDOI2009]晨跑 最小费用最大流的板子题吧 令 \(i'=i+n\) \(i -> i'\) 建一条流量为1费用为0的边这样就不会对答案有贡献 其次是对 \(m\) 条边建 \(u'-& ...

  9. jquery的封装与对象学习

    1.封装学习 /// <reference path="http://apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js" /> ...

  10. C++ lvalue(左值)和rvalue(右值)

    lvalue(左值)和rvalue(右值) 昨天写代码遇见一个这样的错误:{ "cannot bind non-const lvalue reference of type 'int& ...