[龙之谷专题]MSH模型转换器开发日志<放出源代码>

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

前言

    这个程序以及相关资信是自己兴趣写出来的,没有任何商业利益的,本程序仅用于学习研究之用,请勿用于商业用途,由此软件产生的商业纠纷软件作者一概不负责任.
    发现上一篇的龙之谷修改专题日志不少人关注的说,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 SRC
演示视频上的琪露诺冰翼 点击下载

文件结构

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.支持非英文目录
2012.9.22 – V1.2
1.放出源代码,停止工程

  1. 暂无评论

  1. 暂无 Trackback



return top