第三讲 mdl模型的文本编辑及认知——解读mdl文件骨骼动作部分的数据结构
首先大家下载一下这个附件,然后用记事本打开它,按我说的一步一步对照着做
加注解的mdl.rar
(11 KB, 下载次数: 380)
用记事本打开这个mdl,首先看这里
- //Modified with MdlVis.
- Version {
- FormatVersion 800,
- }
- Model "WarHorse" {
- NumGeosets 2,
- NumGeosetAnims 2,
- NumBones 28,
- BlendTime 150,
- }
复制代码
Geosets代表着多边形的数量,GeosetAnim表示整个模型的动作(这里包括普通动作和全局动作)的总数
而Bones代表着骨骼的数量 这里的骨骼指的仅仅是Bone,也就是咱们在mdlvis里看到的绿色小方块,Bones是和绑定在多边形上的点绑定,并带动多边形活动的骨骼
除了Bones,骨骼还有其他几种,分别是是Helpers、Lights、Attachments和ParticleEmitters2以及Events
Helpers是骨骼索引项,在mdlvis里也是绿色的小方块
Lights 顾名思义,就是灯光
Attachments是特效连接点,也就是咱们所说的Overhead Ref、Weapon Ref这些在地图里连接其他模型的点,在mdlvis里它们是紫色的三角形
ParticleEmitters 2是粒子发射器,也就是咱们做粒子的特效点,在mdlvis里它们是绿色的三角形
Events就是追加事件点,用于在游戏中引用声音、溅血效果、脚印、模型、死亡动画等
以上六种就是骨骼的六类,在一个模型中,总骨骼数就是它们五项的总和
接下来是这里:
- GlobalSequences 1 {
- Duration 800,
- }
复制代码
在这里GlobalSequences 1 表示的是全局动作的数量,这里1就表示这个模型里只有一个全局动作,而Duration 800 代表着第一个全局动作,800表示这个动作共有800帧,另外这个全局动作因为是排在第一个,所以它的id为0
然后是这个
- Sequences 3 {
- Anim "Stand" {
- Interval { 67, 1400 },
- MinimumExtent { -30.1583, -42.9656, 1.98352 },
- MaximumExtent { 58.508, 43.4287, 115.253 },
- BoundsRadius 72.5044,
- }
- Anim "Stand - 2" {
- Interval { 1500, 3500 },
- Rarity 3,
- NonLooping,
- MinimumExtent { -34.1328, -41.5903, 1.98352 },
- MaximumExtent { 65.3825, 48.3837, 115.419 },
- BoundsRadius 74.5889,
- }
- Anim "Walk" {
- Interval { 78100, 78933 },
- MoveSpeed 240,
- MinimumExtent { -53.0536, -46.2613, -0.725337 },
- MaximumExtent { 51.0393, 61.0081, 122.376 },
- BoundsRadius 74.1719,
- }
复制代码
这一段在你们那个文件里没有,因为这个模型里没有一般动作,但在大多数模型里这语句是有的,所以大家听就是了。
在这里 Sequences 3 表示这个模型一共有三个普通动作 3表示普通数量 然后,红色部分Anim "Stand" 、Anim "Stand - 2" 和Anim "Walk"表示的是动作的名称 绿色部分Interval { 67, 1400 }, 和 Interval { 1500, 3500 },以及Interval { 78100, 78933 },表示的是动作的帧数范围 棕色部分 Rarity 3, 表示 Stand -2 这个动作出现的概率,3表示此动画出现的概率为3级(魔兽动画出现概率共9级,1级出现频率最大,9级最小) 紫色部分 MoveSpeed 240, 表示Walk(行走动画)的移动速度,即标识在速度为240且动画按原速率播放时动画不会产生“滑步”效应。与WE中物体编辑器的单位的属性Speed配合使用。如:当在单位编辑器中将移动速度设为270时,系统将把行走动画的播放速率加快到原来的270/240倍(1.125倍),从而有效的消除了“滑步”效应。很多人很多往往没注意这个细节,所以动画真实性大打折扣。
粉色部分 NonLooping,表示该动作为不循环动作,只播放一次,没有此说明的时候默认为循环动作,多用于Death、Dissipate等等动作 橙色部分 - MinimumExtent { -53.0536, -46.2613, -0.725337 },
- MaximumExtent { 51.0393, 61.0081, 122.376 },
- BoundsRadius 74.1719,
复制代码
前两行表示模型运动的边界盒,对角顶点坐标,第三行表示模型运动的范围半径
下面这部分你的文件里也没有,但是有些多边形带显隐动作的就会有这部分语句,这里只是给大家引一个例子,大家跟着听就是了
- GeosetAnim {
- Alpha 21 {
- DontInterp,
- 67: 0,
- 1500: 0,
- 13200: 1,
- 13267: 0,
- 13333: 1,
- 13400: 0,
- 13467: 1,
- 13533: 0,
- 13600: 1,
- 13667: 0,
- 13733: 1,
- 13800: 0,
- 13900: 1,
- 13967: 0,
- 14333: 0,
- 16167: 0,
- 78100: 0,
- 83867: 0,
- 146033: 0,
- 176433: 0,
- 212833: 0,
- }
- static Color { 0.105882, 0.611765, 1 },
- GeosetId 0,
- }
复制代码
Alpha 21 代表这个显隐动画,告诉系统在什么时候隐藏或显示物体,21表示有21个关键帧
DontInterp, 表示这个动画的控制器是on/off 型的,即0的时候不显示,1的时候显示。
static Color { 0.105882, 0.611765, 1 }, 这是设置这个带有显隐动画的多边形色相的地方。格式:{ 蓝,绿,红 },最大值是1,1就相当于photoshop中颜色定义的255
GeosetId 0, 表示这个显隐动画用在整个模型中的第一个多边形里,0是多边形的id,0就表示第一个。
接下来在咱们的文件中搜索这个,为了方便,我就直接在后面标注了
- Bone "bone_b0" { 骨骼名
- ObjectId 0, 这个是骨骼id,0就表示第一个骨骼
- GeosetId Multiple, 指这个骨骼相连的几何体的id,后面的Multiiple指的是多重几何体
- GeosetAnimId None, 指这个骨骼所应用的全局动作的id号,这里是None,也就是说这个骨骼没用到它
- Translation 25 { 还记不记得上一讲中所讲的模型运动的三种形式?Translation就是三种形式中的平移,这里指的是这个骨骼的平移关键帧一共有25个,该属性的运动轨迹格式为 关键帧时间:{ x坐标,y坐标,z坐标 },其他属性参考第二讲
- Linear, 控制器的属性,Linear表示属性为线性,
- GlobalSeqId 0, 这一行就表示下面的骨骼运动为全局动作 0是循环调用的是全局动作的id号,也就是代表第一个全局动作,就是刚才800帧的那个
- 0: { -0.714844, -0.008605961, 2.15625 }, 运动轨迹数据,格式为 关键帧时间:{ x坐标,y坐标,z坐标 },具体讲解参看第二讲
- 34: { -0.225586, -0.008605961, 2.78125 },
- 67: { 0.339844, -0.008605961, 3.25 },
- 100: { 0.949219, -0.008605961, 3.5625 },
- 134: { 1.57813, -0.008605961, 3.6875 },
- 167: { 2.1875, -0.008605961, 3.46875 },
- 200: { 2.75, -0.008605961, 2.89063 },
- 234: { 3.23438, -0.008605961, 2.03125 },
- 267: { 3.625, -0.008605961, 0.988281 },
- 300: { 3.89063, -0.008605961, -0.144531 },
- 334: { 3.98438, -0.008605961, -1.27344 },
- 367: { 3.84375, -0.008605961, -2.3125 },
- 400: { 3.5, -0.008605961, -3.17188 },
- 434: { 2.98438, -0.008605961, -3.75 },
- 467: { 2.34375, -0.008605961, -3.96875 },
- 500: { 1.63281, -0.008605961, -3.85938 },
- 534: { 0.894531, -0.008605961, -3.54688 },
- 567: { 0.179688, -0.008605961, -3.0625 },
- 600: { -0.458984, -0.008605961, -2.45313 },
- 634: { -0.976563, -0.008605961, -1.74219 },
- 667: { -1.32031, -0.008605961, -0.960938 },
- 700: { -1.45313, -0.008605961, -0.144531 },
- 734: { -1.35938, -0.008605961, 0.667969 },
- 767: { -1.10156, -0.008605961, 1.44531 },
- 800: { -0.714844, -0.008605961, 2.15625 },
- }
- Rotation 25 { 表示这个骨骼的旋转关键帧一共有25个, Rotation值得就是运动的三种形式中的旋转,也是骨骼最普遍运动的形式,旋转运动的格式为关键帧时间:{ 以x为主轴的顺时针转角,以y为主轴的顺时针转角,以z为主轴的顺时针转角,第四个值与前三个值所构成四元数 } 注:Quaternions(四元数)见DirectX9的说明,是用于转动平滑过渡的一项
- Linear, 控制器属性仍为线性
- GlobalSeqId 0, 表示下面的骨骼运动为全局动作 0是循环调用的是全局动作的id号,代表第一个全局动作
- 0: { 0, -0.0102539, 0, 0.996094 }, 运动轨迹数据,格式为关键帧时间:{ 以x为主轴的顺时针转角,以y为主轴的顺时针转角,以z为主轴的顺时针转角,第四个值与前三个值所构成四元数 }
- 34: { 0, -0.0153809, 0, 0.996094 },
- 67: { 0, -0.0197754, 0, 0.996094 },
- 100: { 0, -0.0233154, 0, 0.996094 },
- 134: { 0, -0.0256348, 0, 0.996094 },
- 167: { 0, -0.0264893, 0, 0.996094 },
- 200: { 0, -0.0239258, 0, 0.996094 },
- 234: { 0, -0.0178223, 0, 0.996094 },
- 267: { 0, -0.0106201, 0, 0.996094 },
- 300: { 0, -0.00473023, 0, 1 },
- 334: { 0, 0, 0, 1 },
- 367: { 0, 0.00527954, 0, 1 },
- 400: { 0, 0.010498, 0, 0.996094 },
- 434: { 0, 0.0151978, 0, 0.996094 },
- 467: { 0, 0.019165, 0, 0.996094 },
- 500: { 0, 0.0217285, 0, 0.996094 },
- 534: { 0, 0.0227051, 0, 0.996094 },
- 567: { 0, 0.0218506, 0, 0.996094 },
- 600: { 0, 0.0195313, 0, 0.996094 },
- 634: { 0, 0.0161133, 0, 0.996094 },
- 667: { 0, 0.0116577, 0, 0.996094 },
- 700: { 0, 0.00650024, 0, 1 },
- 734: { 0, 0.0009765631, 0, 1 },
- 767: { 0, -0.00469971, 0, 1 },
- 800: { 0, -0.0102539, 0, 0.996094 },
- }
- }
- Bone "bone_b1" { 骨骼名
- ObjectId 1, 这个是骨骼id,1就表示第二个骨骼
- Parent 0, 表示这块骨骼是以id为0的骨骼作为父骨骼,即bone_1是以bone_b0为父骨骼
- GeosetId Multiple,
- GeosetAnimId None,
- Rotation 25 {
- Linear,
- GlobalSeqId 0,
- 0: { 0.00369263, -0.0427246, 0.0228272, 0.996094 },
- 34: { 0.0020752, -0.0429688, 0.0194092, 0.996094 },
- 67: { 0.00100708, -0.0424805, 0.0159912, 0.996094 },
- 100: { 0.000518799, -0.0410156, 0.0125122, 0.996094 },
- 134: { 0.00732422, -0.0385742, 0.00891113, 0.996094 },
- 167: { 0.0224609, -0.0358887, 0.00543213, 0.996094 },
- 200: { 0.0375977, -0.0327148, 0.00247192, 0.996094 },
- 234: { 0.0444336, -0.029419, 0.000427246, 0.996094 },
- 267: { 0.0441894, -0.0262451, -0.0007019041, 0.996094 },
- 300: { 0.0432129, -0.0233154, -0.00100708, 0.996094 },
- 334: { 0.0417481, -0.0211182, 0.000335693, 0.996094 },
- 367: { 0.0397949, -0.0196533, 0.00372314, 0.996094 },
- 400: { 0.0375977, -0.0192871, 0.00848389, 0.996094 },
- 434: { 0.0351563, -0.0197754, 0.0141602, 0.996094 },
- 467: { 0.0322266, -0.0211182, 0.0200195, 0.996094 },
- 500: { 0.029419, -0.0229492, 0.0256348, 0.996094 },
- 534: { 0.0262451, -0.0251465, 0.0303955, 0.996094 },
- 567: { 0.0230713, -0.0275879, 0.0336914, 0.996094 },
- 600: { 0.0198975, -0.0302734, 0.0349121, 0.996094 },
- 634: { 0.0167236, -0.032959, 0.0344238, 0.996094 },
- 667: { 0.0137329, -0.0354004, 0.0332031, 0.996094 },
- 700: { 0.0108032, -0.0378418, 0.0314941, 0.996094 },
- 734: { 0.00811768, -0.0400391, 0.0290527, 0.996094 },
- 767: { 0.00573731, -0.0415039, 0.0261231, 0.996094 },
- 800: { 0.00369263, -0.0427246, 0.0228272, 0.996094 },
- }
- }
复制代码
下面是这个,这一块是骨骼连接点运动轨迹的数据,在我给你们的文件里也没有,你们就听吧
- Attachment "Foot Left Ref " { 骨骼连接点的名称
- ObjectId 46, 骨骼连接点的id,这个id序号是承接其他类型骨骼id的,比如前面有24个Bones和1个Lights,那么这第一个Attachment 的id就是24(25+1-1)
- Parent 33, // "Bone_Foot_L" 父骨骼的id号以及父骨骼的名称
- Visibility 1 { 可见度动画关键帧,如果特效链接点变得不可见了,那么它上面的特效也不可见了,所以单位死亡时很多特效就消失了,因为动画片断“Death”包含下面的关键字的时间:212833毫秒
- DontInterp,
- 212833: 0,
复制代码
接下来搜索下面语句,这里是所有骨骼轴心点的坐标,也就是是所有有objectId的物体的轴心点坐标的存放处,骨骼的实质就是一个4×4的带有objectID矩阵,所有带有objectID的物体都是要有轴心点定位的 - PivotPoints 28 { 这里表示一共有28个轴心点坐标(你可以理解为这个模型一共有28个骨骼,这28个骨骼的坐标)
- { 27.0661, 0, 83.9989 }, objectId为0的骨骼的轴心点坐标
- { 27.4143, 0, 83.5726 }, objectId为1的骨骼的轴心点坐标
- { 28.6196, 0, 84.037 }, objectId为2的物体的轴心点坐标
- { -1.58158, 0, 87.3155 }, 顺序以此类推
- { 47.3672, 0, 93.8186 },
- { 50.7213, 12.854, 63.8412 },
- { 50.7214, -12.854, 63.8411 },
- { -37.5628, 0, 90.3476 },
- { -18.437, 13.71, 82.9747 },
- { -18.437, -13.71, 82.9747 },
- { 59.7905, 0, 104.899 },
- { 44.5219, 12.5948, 34.2097 },
- { 44.5219, -12.6322, 34.2094 },
- { -43.747, 0, 87.0709 },
- { -20.9027, 11.7635, 52.7242 },
- { -20.8959, -11.8407, 52.7188 },
- { 76.7466, 0, 113.965 },
- { 39.8998, 12.4017, 12.1176 },
- { 39.8997, -12.4671, 12.1171 },
- { -48.5984, 0, 72.5167 },
- { -34.7786, 11.0703, 42.7343 },
- { -34.7838, -11.226, 42.7404 },
- { 87.0801, 0, 87.8452 },
- { 89.4633, 5.99194, 113.759 },
- { 88.6335, -5.64075, 113.351 },
- { -47.5813, 0, 45.3669 },
- { -37.8849, 9.01504, 12.8335 },
- { -37.885, -9.25456, 12.8335 },
- }
复制代码
下面的语句是粒子动画的数据,具体如下
- ParticleEmitter2 "BlizParticle07attack01" {
- ObjectId 56, 粒子特效点的id
- Unshaded, 粒子着色忽略灯光影响
- static Speed 240, 粒子速度
- static Variation 0.71, 粒子速度变化率
- static Latitude 0, 发射角
- static Gravity 0, 引力大小
- Visibility 21 { 可见度,前面讲了,没什么好讲的
- DontInterp,
- 67: 0,
- 1500: 0,
- 13200: 1,
- 13267: 0,
- 13333: 1,
- 13400: 0,
- 13467: 1,
- 13533: 0,
- 13633: 1,
- 13700: 0,
- 13767: 1,
- 13833: 0,
- 13900: 1,
- 13967: 0,
- 14333: 0,
- 16167: 0,
- 78100: 0,
- 83867: 0,
- 146033: 0,
- 176433: 0,
- 212833: 0,
- }
- LifeSpan 0.1, 粒子寿命
- static EmissionRate 40, 粒子每秒发射数量
- static Width 12, 粒子发射器的宽度
- static Length 12, 粒子发射器的长度
- Additive, 粒子是加性透明
- Rows 1, 粒子的贴图有1行
- Columns 1, 粒子的贴图有1列
- Tail, 粒子为脱尾模式
- TailLength 0.5, 粒子尾巴的长度
- Time 0.6, 粒子动画中点的是在粒子寿命的百分之多少
- SegmentColor { 粒子颜色动画,格式:Color { 蓝,绿,红 }
- Color { 1, 1, 1 }, 粒子诞生时的颜色
- Color { 1, 1, 1 }, 粒子中点的颜色
- Color { 1, 1, 1 }, 粒子消亡时的颜色
- },
- Alpha {167, 157, 0}, 粒子透明度动画,格式:Alpha { 粒子诞生时透明度,粒子中点时透明度,粒子消亡时透明度
- }
- ParticleScaling {1.3, 0.6, 0.001}, 粒子缩放动画,也是诞生,中点,消亡时的值
- LifeSpanUVAnim {0, 0, 1}, 粒子贴图动画,下面也是,只是部位不同
- DecayUVAnim {0, 0, 1},
- TailUVAnim {0, 0, 1},
- TailDecayUVAnim {0, 0, 1},
- TextureID 5, 贴图id
- Translation 1 { 平移运动关键帧为1,和前面一样,注意这里的控制器的属性是Bezier(矢量曲线),它的格式为
- 关键帧时间:{ 以x为主轴的顺时针转角,以y为主轴的顺时针转角,以z为主轴的顺时针转角,第四个值与前三个值所构成四元数 }
- InTAn{ 以x为主轴的顺时针转角,以y为主轴的顺时针转角,以z为主轴的顺时针转角,第四个值与前三个值所构成四元数 }
- OutTan { 以x为主轴的顺时针转角,以y为主轴的顺时针转角,以z为主轴的顺时针转角,第四个值与前三个值所构成四元数 }
- InTAn为关键帧出射值
- OutTan为关键帧入射值
- Bezier,
- 13200: { 19.1686, -28.3813, 22.6433 },
- InTan { 19.1686, -28.3813, 22.6433 },
- OutTan { 19.1686, -28.3813, 22.6433 },
- }
- Rotation 1 { 旋转运动关键帧为1
- Hermite, 控制器属性为Bezier和TCB
- 13200: { 0, -0.707107, 0, -0.707107 },
- InTan { 0, -0.707107, 0, -0.707107 },
- OutTan { 0, -0.707107, 0, -0.707107 },
- }
- }
复制代码
最后讲的是追加事件Events部分的文本内容,如下:
- EventObject "SNDxDRIF" { 这句的意思是在14333毫秒时播放代码为DRIF的声音
- ObjectId 57, Events骨骼的id为57
- EventTrack 1 { Events时间运动关键帧的数量为1
- 14333, 代码执行时刻,第14333毫秒
- }
- }
- EventObject "FPTxFBR0" { 这句的意思是在78300毫秒时在Foot Right链接点上放置一个代码为FBRO的脚印
- ObjectId 58,
- EventTrack 1 {
- 78300,
- }
- }
- EventObject "FPTxFBL0" { 这句的意思是在78733毫秒时在Foot Left链接点上放置一个代码为FBLO的脚印
- ObjectId 59,
- EventTrack 1 {
- 78733,
- }
- }
- EventObject "SPLxHBS3" { 这句的意思是在14433毫秒时开始喷血,血的模型代码是HBS3,下面的语句以此类推
- ObjectId 60,
- EventTrack 1 {
- 14433,
- }
- }
复制代码
EventObject是/用于在游戏中引用声音、溅血效果、脚印、模型、死亡动画等的一种骨骼
EventObject后面引号里的就是事件名称,名称是有固定格式的,且不同类型的事件它的格式也不同:
SNDx????表示声音,后面的????是4位代码,代码值可查询art tool的官方说明
FPTx????表示脚印
SPNx????表示产出效果
SPLx????是溅血
这一讲是模型骨骼动作合并中最难的一部分,但也是将多个带动作的模型合为一体的基础和前奏,所以,想掌握这种技术的人一定要认真去看,理解才行,具体怎样合并模型动作,请听下回分解
|