[龙之谷专题]MSH模型转换器开发日志<已停止>

maya_snap_20101205

龙之谷模型转换器开发进程表
功能 项目 读取 写入
多边形 贴图 骨骼 多边形 贴图 骨骼
命名 顶点 索引 法线 命名 坐标 节点 权重 命名 顶点 索引 法线 命名 坐标 节点 权重
设计/D
实现/A
测试/T
额外功能 多Mesh UI界面 材质支持 × 杂项 - 开发进度 Release
开发状态 V1.2 下载   基本完成   遇到问题   未解决 更新日期 03.31

maya_snap_20101217

前言

    这个程序以及相关资信是自己兴趣写出来的,没有任何商业利益的,本程序仅用于学习研究之用,请勿用于商业用途,由此软件产生的商业纠纷软件作者一概不负责任.
    发现上一篇的龙之谷修改专题日志不少人关注的说,QQ和MSN上也有问道开发情况的,看来修改龙之谷的模型还是多数CGer的共同愿望呢~于是乎有了这篇文章~嘛,我也知道等待的滋味不好受的,所以就贴一下每天的开发进度吧,稍后还会贴出相关信息~
    最后,还请各位原谅本人不才,拖慢了开发进度了orz……
    * 关于龙之谷的msh资源结构,大部分信息源于 liuliqiang 大大,特此感谢提供!

使用说明

<-Display English version of usage->

    "龙之谷MSH模型转换器"是一款用于龙之谷模型文件(*.msh)与其他通用模型文件相互转的便捷工具.
使用时只需指定msh文件位置,以及msh对应的动画文件(*.ani),即可输出通用模型格式到指定目录.

MSH格式->通用模型格式:

  1. 点击"浏览…"按钮指定MSH文件位置.
  2. 点击"浏览…"按钮指定MSH对应的ANI位置.
  3. 点击"转换"按钮,选择所需转换格式,指定输出目录及文件名称.
  4. 转换完成.

通用模型格式->MSH格式:

  1. 点击"浏览…"按钮,指定通用模型文件位置.
  2. 点击"转换"按钮,选择MSH格式,指定输出目录及文件名称.
  3. 转换完成.

资源链接

视频教程:
[妹汁谷]MSH模型格式转换工具使用说明 点击跳转
龙之谷时装补丁制作之进阶教程 经验分享 点击跳转

下载地址:
龙之谷MSH模型转换器1.2 中文版 English Version
演示视频上的琪露诺冰翼 点击下载

文件结构

MSH文件结构示意
Header 文件头部,用于索引各种数据
BoneData 骨骼数据部分,大小由骨骼数量决定
MeshData 模型数据部分,大小由Mesh数量决定
OtherData 其他数据部分,大小由其他元素量决定

Header部分

Header结构示意
  name: 文件头标识
name[256] version: 文件版本
  meshCount: Mesh总数
version meshCount unknown unknown bbMax: BoundingBox最大值
bbMax   bbMin: BoundingBox最小值
bbMin boneCount unknown boneCount: 骨骼总数
otherCount   otherCount: 其他元素总数
1
2
3
4
5
6
7
8
9
10
11
12
struct Header{
    char name[256];	//Eternity Engine Mesh File 0.1
    int version;
    int meshCount;
    int unknown1;	//0x1
    int unknown2;	//0x0
    Vec3F bbMax;
    Vec3F bbMin;
    int boneCount;
    int unknown2;	//0x1或0x0
    int otherCount;
};

BoneData部分

    骨骼数据个数由Header索引,从文件头开始偏移0×400(1024)字节即为骨骼数据:

单个BoneData结构示意
boneName[256] boneName: 骨骼名称
m1 m1: 骨骼变换矩阵第一行数据
m2 m2: 骨骼变换矩阵第二行数据
m3 m3: 骨骼变换矩阵第三行数据
m4 m4: 骨骼变换矩阵第四行数据
1
2
3
4
struct BoneData{
	char boneName[256];			//骨骼名称
	Vec4F transformMatrix[4];	//骨骼变换矩阵
};

MeshData部分

    MeshData部分由一个或多个Mesh数据组成,具体多少个Mesh由文件头部的meshCount决定.
每个Mesh数据由Mesh信息+Mesh数据组成,为了方便演示,示意图将把Mesh信息部分和Mesh数据部分合并一起表示,而具体实现代码将分成两个结构体:

单个MeshData结构示意
sceneRoot[256] sceneRoot: Mesh所属节点名称
  meshName: Mesh名称
meshName[256] vertexCount: 顶点个数
  indexCount: 顶点(三角面)索引数
vertexCount indexCount unknown renderMode renderMode: 渲染模式,取值0×100/0×101
empty[512-16] (GL_TRIANGLE_STRIP/GL_TRIANGLE)
vertexIndex vertexIndex: 顶点索引,indexCount个元素
vertexData vertexData: 顶点数据,vertexCount个元素
normalData normalData: 法线数据,vertexCount个元素
uvData uvData: UV贴图数据,vertexCount个元素
weightIndex weightIndex: 权重索引,vertexCoun个元素
weightData weightData: 权重数据,vertexCount个元素
boneCount   boneCount: Mesh绑定骨骼个数
boneIndex boneIndex: 骨骼索引,boneCount个元素
1
2
3
4
5
6
7
8
9
struct MeshInfo{
	char sceneName[256];
	char meshName[256];
	int vertexCount;
	int indexCount;
	int unknown;
	int renderMode;
	char empty[512 - 16];
};
1
2
3
4
5
6
7
8
9
10
struct MeshDataPointer{//数据指针
    char* pFaceIndex;	//0x2(unsigned short) * indexCount
    char* pVertexData;	//0x4(float) * 3 * vertexCount
    char* pNormalData;	//0x4(float) * 3 * vertexCount
    char* pUVData;	//0x4(float) * 2 * vertexCount
    char* pBoneIndex;	//0x2(unsigned short) * 4 vertexCount
    char* pBoneWeight;	//0x4(float) * 4 * vertexCount
    int*  pBoneCount;	//Mesh绑定的Bone数
    char* pBoneName;	//0x100(char [256]) * boneCount
};

    现在说一下MeshData里面各个元素的组成,虽然说规范和DirectX差不多,不过当时对DirectX的3D编程完全没有了解的我,可被这个搞得一头冒水呢……
    MSH文件在保存浮点型数据时均使用单精度型(float)浮点数保存数据.

VertexData元素
    VertexData,即顶点数据,是顶点在三维空间的x,y,z坐标数据.每个元素使用Vec3F结构保存数据.

VertexIndex元素
    VertexIndex,即顶点索引,是程序画面的顺序数据,索引的是顶点数据.每个元素使用unsign short类型保存数据.

NormalData元素
    NormalData,即法线数据,是每个顶点的法向数据,以三维空间坐标x,y,z表示.每个元素使用Vec3F结构保存数据.

UVData元素
    UVData,即UV贴图数据,是每个顶点在二维贴图空间映射的u,v坐标.每个元素使用Vec2F结构保存数据.

WeightIndex元素
    WeightIndex,即权重索引,是每个顶点的权重索引,每个顶点最多可以索引4个骨骼.每个元素使用4个unsign short类型保存数据.

WeightData
    WeightData,即权重数据,是每个顶点的权重数据,每个顶点最多可以拥有4个骨骼权重.每个元素使用Vec4F结构保存数据.

BoneIndex
    BoneIndex,即骨骼索引,用以给骨骼编序,只保存骨骼名称.每个元素使用char [256]字符型数组保存数据.

OtherData部分

    暂时猜测该部分数据可能用于武器的"刀锋"特效.

自定义结构

1
2
3
4
5
6
7
8
9
10
11
12
class Vec2F{
	public:
	float x;
	float y;
	Vec2F(){x = 0; y = 0;}
	Vec2F(KFbxVector2 &vector){
		x = vector.GetAt(0);
		y = vector.GetAt(1);}
	Vec2F(KFbxVector4 &vector){
		x = vector.GetAt(0);
		y = vector.GetAt(1);}
};
1
2
3
4
5
6
7
class Vec3F : public Vec2F{
	public:
	float z;
	Vec3F() : Vec2F(){z = 0;}
	Vec3F(KFbxVector4 &vector) : Vec2F(vector){
		z = vector.GetAt(2);}
};
1
2
3
4
5
6
7
class Vec4F : public Vec3F{
	public:
	float w;
	Vec4F() : Vec3F(){w = 0;}
	Vec4F(KFbxVector4 &vector) : Vec3F(vector){
		w = vector.GetAt(3);}
};

Change Log

11.18 
A03:解决建立三角面时顺序错误的问题.
T02:顶点信息建立测试通过.
T03:三角面建立测试通过.
T04:顶点法线建立测试通过.
11.19
A06:完成了对贴图UV的读取.
T02/T04/T06:发现浮点数的精度取值问题.
11.20
A01/A05:完成对模型名称,贴图名称读取.
T01/T05:模型名称,贴图名称读取通过测试. 
11.21
重新理解MSH格式结构.
重写了一下读取函数,优化读取速度,整理了程序结构.
A03:修复了奇偶面数读取错误问题.
T03:奇偶面数读取测试通过.
11.23
模块化功能函数.
A07:实现骨骼结点名称的读取.
T07:骨骼结点名称读取测试通过.
D08:读取骨骼变换矩阵遇到问题.
11.26
T03:发现在读取非闭合多边形出现三角面混乱问题.
D08:完成对骨骼数据的读取设计.
A08:考虑绑定骨骼绑定问题.
11.27
发现不同版本的MSH在建立多边形时采用GL_TRIANGLE_STRIP 或 GL_TRIANGLE 模式
T03:解决读取顶点索引错乱问题.
A11:写入MSH顶点索引可能要使用GL_TRIANGLE模式
11.28
A08:完成对骨骼与模型的绑定已经蒙皮权重的添加.
A08:遇到绑定骨骼后模型扭曲的问题.
11.29
MSH文件不足以提供完整骨骼信息,决定追加ANI文件辅佐.
12.05
A08:完成对骨骼父子节点的添加,修正世界坐标和本地坐标的转换问题.
D08:修正骨骼与模型绑定后扭曲问题.
T08:骨骼绑定测试通过.
O01:完成对多Mesh读取
12.09
D11:决定使用GL_TRIANGLE模式写入三角形索引.
A15:实现对骨骼名称及骨骼变换矩阵的写入.
T15:发现写入的变换矩阵与原数据有些差异.
12.10
D09/D10/D11/D12:实现对Mesh名称,三角面索引,顶点数据,法线信息的读取和写入.
D13/D14:实现对贴图坐标名称的读取和写入.
D16:实现对骨骼权重的读取和写入.
T15:仍未解决骨骼矩阵信息与原信息差异问题,但测试中未发现有什么问题.
T09/T10/T11/T12/T13/T14/T16:测试通过,但是无法保证BoundingBox信息正确.
"今天只有早上一节物理课,于是果断花了一整天把这个程序的大部分功能实现了.毕竟这周学校要忙的事特多,搞到周一到周四基本上不能碰程序了…果然有了读取的经验和知识,写入的编程设计进度一天就完成了…激动~~"
12.11
A03:优化了GL_TRIANGLE_STRIP读取多边形算法
T03:发现某系模型转换成FBX格式导入到Maya后再导出FBX会导致Maya崩溃的问题.
12.13
T15:解决骨骼世界变换矩阵数据的出现差异的问题,发现原来是编写时忽略了骨骼根节点.
12.14
发布1.0b,公测开始……
2010.12.17 – V1.0.1b
1.修复了UV贴图错误问题.
2.解决骨骼名称特殊字符过滤问题
2011.1.16 – V1.1
1.界面支持视觉风格
2.更详细错误提示信息
3.可选额外骨骼信息(ANI文件需求)
4.增加对新版FBX格式的兼容性
2011.3.31 – V1.2
1.修正界面刷新异常
2.UNICODE工程
3.支持非英文目录

    • 小笛甘比
    • 八月 28th, 2011

    GPBeta :只要是角色用的话都可以用角色的主ani…怪的话也是,直接用怪的主ani就好了~

    ……转换翅膀的时候又出老毛病了OTL 说C++……用的是翅膀自身的ANI

    • Emanoelk
    • 九月 1st, 2011

    Hey, Are you able to put in this update in;
    Convert several .msh to .fbx files?
    Kind of annoying to convert them one at time..
    Thanks.

    • lsn
    • 九月 25th, 2011

    大大 能导出动画么?

    • lsn
    • 九月 25th, 2011

    GPBeta :=3=不能的说…

    我想要动画啊 没有继续开发动画导出功能的计划了额

    • 牧歌
    • 十月 10th, 2011

    LZ大人你的这个工具非常的好用,
    只是近期更新学者这个职业后,这个MSN转换貌似无法支持完整的学者模型骨架转换回去,而导致修改后的模型游戏上显示无法被蒙皮的效果.望请LZ解答一下.

    • 诶?!
      囧么会酱紫…莫非数据有改动?!
      你检查一下使用的ANI大小正确不?

    • ikuto
    • 一月 4th, 2012

    hi i have problem when convert .obj or .3ds to .msh
    it’s return successful but .msh file always 1kb.

    try convert back to .obj it’s empty.

    i’m using Blender export .obj or .3ds file

    • hi~
      this program is based on the Autodesk FBX SDK, & fbx is the recommanded format.
      btw, obj format doesn’t support skeletons so you will get least problems if you export your models as fbx format
      have fun :)

    • ikuto
    • 一月 8th, 2012

    Hi.

    Thanks For Reply It’s help me lot..
    I have another problem..
    When binding Face with skeleton (bind skin->smooth bind) then convert to fbx->msh.. it’s work fine.. (some vertex goes wrong direction.)
    But when I edit attribut after smooth skin (componen editor->smoth skin) for better sync with ani in game it successfull convert until msh and pak… but in game/DNModelBrowser I got crash..

    I’m using maya 2012.. it this converter support fbx from maya 2012?

    regards.

    • nice to see you again.

      i think this problem may caused by the over-bingding. as i mentioned in the usage, DN mesh supports 4 skeleton nodes per vertex, make sure there’s no more than 4 nodes are bound to 1 vertex. if a node is not nacessary for some parts, you should simply not select it when you do the “smoth bind” or manually remove it from a vertex.

      at the end, this converter is tested only on a few vers of maya (2012 is not included XD), but fbx should be compatible in most cases… however, choosing a lower fbx version when you export your models in maya could meet less problems …

      hope these would be helpful for you. :)

    • 牧歌
    • 一月 16th, 2012

    GPBeta :诶?!囧么会酱紫…莫非数据有改动?!你检查一下使用的ANI大小正确不?

    ANI是正确的,真是变动了,可能因为新职业的骨架变动了很多节点…..

    • ikuto
    • 一月 25th, 2012

    Hi :)

    I’ve solved binding issue, thanks to your reply.

    I got another issue.. I didn’t know if this issue because of your converter or not.. but I got wrong texture when rendering on DNModelBrowser / in the game.

    here link of picture
    http://i1135.photobucket.com/albums/m629/achridhan/badtex.jpg

    I make sure that texture and UV’s are match on maya.. you can see on picture that texture are good enough. but after convert to msh and render, the texture goes wrong..

    hope you can enlighten my path again. :D

    best regards.

    • oh i see.
      this problem has been recognized & we assume that it’s caused by the standard of the msh format, which requires each UV point ONLY maps to one vertex.
      well,in other words, you just need to splite your mesh model according to your UV map, then your models will mess up no more

      uh…i not sure whether i could describe & explain exactly with my poor english, but if i don’t,just ask me in anytime :)

    • kawayide
    • 三月 22nd, 2012

    impressive work!

    may I ask BoneData’s TransformMatrix is local transform or global?

    • thanks!
      the transform matrix describe local coordinate / rotation / scaling infomations.
      use a bruch of another transform matrices to restore the bones’ animation.

    • sharow
    • 三月 26th, 2012

    代LZ回复一下大家关于:Ani格式的问题

    .ani格式
    文件头
    struct AniHeader{
    char name[256];
    int version;
    int boneCount; //总Bone数
    int animateCount; //总动画数
    };
    后面是每个动画名称
    然后是 uint32 * nAni 的帧数列表,就是每个动画的总帧数

    再后面数据按一个骨骼一个骨骼分的,骨骼数就是文件头中的nBone
    一个骨骼里含有全部动画数据,然后是下一个骨骼,还是含有该骨骼的全部动画数据

    每个骨骼的数据结构为:
    骨骼名字字符串,父骨骼名字字符串
    struct BoneInfo{
    char[256] boneName; //骨骼名称
    char[768] parentName; //父骨骼名称
    };

    然后是每个动画的变换数据(动画个数就是文件头中的nAni):
    每个动画数据的结构为:
    先是一个平移vec3f,一个旋转vec4f,一个缩放vec3f,这个是该动画初始帧的变换

    后面是一个uint32,表示平移变换个数:
    n个平移变换结构:一个uint16的帧数,一个vec3f

    再后面还是一个uint32,表示旋转变换个数:
    n个旋转变换结构:一个uint16的帧数,一个vec4f

    再后面还是一个uint32,表示缩放变换个数:
    n个缩放变换结构:一个uint16的帧数,一个vec3f

    {
    struct AnimateBaseData
    {
    Vec3F Transformation;
    Vec4F Rotation;
    Vec3F Scaling;
    }animateBaseData;
    int transformationCount;
    struct TransformationData{
    unsigned short frameIndex;
    Vec3F data;
    }; // * transformationCount个数据
    int rotationCount;
    struct RotationData{
    unsigned short frameIndex;
    Vec4F data;
    }; // * rotationCount个数据
    int scalingCount;
    struct ScalingData{
    unsigned short frameIndex;
    Vec3F data;
    }; // * scalingCount个数据
    } // * animateCount个数据
    上面是version为11的ani文件格式,version为10不是uint16而是uint32

    version为11,旋转变换不是vec4f,而是四个short,需要转成浮点数再单位化一下

    • 李某人
    • 五月 6th, 2012

    点了转换但是没有新文件生成那是仲么一回事=。=

  1. 还没有引用通告。