芙蕖吧 关注:497贴子:2,676

回复:存档版本,io_scene_烛龙数据V2.6.4_Blender3.3-3.6

只看楼主收藏回复

四、其他说明
目前有3个问题,插件无法处理,需要手动处理:
①古剑2和古剑3导入模型之后,双面网格(重叠网格或者破碎网格)的问题。
这个问题在古剑2阿阮默认服装和古剑3小樱子的冬天外衣上表现十分明显,古剑2阿阮裙子的内侧衣服颜色直接覆盖了外侧的衣服颜色,而古剑3小樱子的冬天外衣上则是内侧和外侧一格一格交错显示,并有玻璃反光效果。
这个问题的根源是游戏使用2层网格重叠表示内外材质(双面材质或双面网格),它们靠得太近,导致Blender渲染在深度裁剪环节上出了问题,产生了错误的渲染结果,解决方法就是把内侧面缩小,使内侧面网格和外侧面网格的顶点不重叠在一起,内侧面和外侧面有合适的微小距离,这样渲染结果就正常了。
这个双面网格没有任何的数据标识,插件无法程序处理,只能靠人工处理。当前插件是默认缩小100倍导入Blender,即使在没有缩小的情况下,双面网格的问题依然存在。而放大导入Blender没有意义,Blender默认的渲染距离是1000m,放大渲染距离,我的电脑上的Blender在拖动操作时会有噪点产生。
手动处理双面网格,操作上是,Blender界面上方点击UV Editing,在右边网格编辑界面选中网格对象,tab进入编辑模式,在左侧UV编辑界面的左上方,点击双向箭头按钮,打开UV顶点与网格顶点联动编辑功能,在UV这边选择内侧面贴图区域内的所有UV顶点,之后鼠标直接移到网格编辑器界面,键盘按下s(缩放),之后键盘数字输入0.95回车。这样内侧面和外侧面就分离了,阿阮外侧衣服颜色正常显示,小樱子的衣服也不会有奇怪的反光效果。
  目前导入古剑2阿阮的模型数据,可以看到她们的网格划分有破碎,我追溯过这个问题,这个属于数据文件便是这样存储的,虽然编辑网格时会让人难受,但只要处理了内侧面的缩小问题,她的显示依然是正常的。我通过Blender中按键按下p键,按选中项分离网格和Ctrl+j合并网格,把破碎的面合并成完整的内侧面,之后再缩放缩小,这样处理后不会影响动画的导入。
②古剑3的材质节点需要手动设置,尤其是眼睛节点。
截止到今天,Blender3.6依然存在不识别古剑3的dds贴图的问题,这个问题从Blender2.8到Blender3.6一直都存在。当前已经通过【dds转png,同时材质通过设置png贴图节点+gamma值】的方式解决。png贴图节点可以设置gamma值1.45达到SRGB空间的显示效果.
古剑3的角色眼睛的渲染方式与古剑3的正常的渲染方式不一样。古剑3的正常渲染方式是基于物理的pbr渲染的方式,类似于Blender的EEVEE渲染,虽然类似,但有区别,所以需要手动处理材质节点,而古剑3眼睛渲染则是另一种完整而逼真的眼睛渲染体系,区别更加明显,需要自己想办法还原效果,这个问题,笔者没有方案。
《剖析Unreal Engine超真实人类的渲染技术Part 2 - 眼球渲染》
https://www.cnblogs.com/timlly/p/11144950.html)。
③古剑123,导入的动画,可能会在中间的某一帧出现问题,所有帧都正常,就这一帧错误,原因暂时不明,需要在Blender自行删除这一帧动画。


IP属地:北京21楼2023-10-18 14:39
回复
    插件历程
    # Nothing happened here in this code, don't mind about it
    from . import 工具, 交互, 接口, 界面, 数据, 文件
    2018年8月份blender2.8Beta发布,其新api的稳定长期支持让笔者认为可以开始着手本插件的开发,且很早之前,笔者从Rich Whitehouse’s Noesis 软件中和Szkaradek123 ‘s Blender249[Gujian2][xac][xsm][2015-03-02]插件中,找到了相关的[.nif]、[.xac, .xsm]文件的python解析代码,这个基础让笔者觉得本插件的开发难度应该不大,故于2018年12月份,笔者从不懂python编程开始,学习python语言和学习blender python api编写插件开始,从第1次让插件在blender插件列表显示可以点选开始,一头扎进了这个前后5年,历经5次重构的本插件的开发中,期间,编写树形数据可视化辅助工具突破16进制解析瓶颈,多方查找资料测试blender内部矩阵空间变换理清骨架及动画导入工作流、多开源软件中寻找查看代码完成古剑3hka动画文件的解析解码,插件代码全部重构试图为后续地图导入做准备。想想,当初纯纯小白的自己,是真不知天高地厚,不知路途坎坷,什么都不知道,不懂不会,就敢一头扎进来,期间磕磕碰碰。最终,感恩上苍恩赐,插件开发过程中在停滞许久后,能如同神赐一般,寻得了解决方式,达到了笔者的预期。笔者水平有限,代码也是东拼西凑,能用挺好。
    下面是一些插件开发过程中的流水账,笔者有些记不清了,大概写写:
    2018年12月,插件__init__初稿,使插件能在blender插件列表中显示出来
    2019年1月,初步完成.nif、.xac网格解析
    2019年2月,初步完成.vmesh,.model网格解析,模型解析陷入瓶颈
    2019年7月,初版辅助工具BytesParserGUI.py,树形数据可视化,二进制解析不在是瓶颈
    2019年8月,辅助工具单BytesParserGUI.py脚本(代码行数几千行)重构为软件,解决辅助工具代码加不进去的感觉
    2019年8月,支持骨架导入,初步理清骨架导入逻辑流
    2020年2月,插件第2次重构开始
    2020年3月,辅助工具维护,添加多文件比较功能
    2020年3月,插件第2次重构完成,版本1.0.0版本,字节解析从struct迁移到numpy
    2020年4月,辅助工具第1版,重构完成,辅助工具可以共用插件相同的文件解析代码
    2020年5月,插件增加dds转png功能,模型解析及导入完成,.kf,.xsm动画解析完成,动画导入未完成
    2020年7月,辅助工具第2版,完成了第2版之后经过测试,废弃使用,仅存档保留
    2020年8月,辅助工具第3版,从前面辅助工具第1版,再次衍生辅助工具第3版
    2021年10月,插件维护
    2022年1月,插件第3次重构开始,感恩上苍恩赐,找到函数能设置edite bone的旋转值,终于能导入动画了。
    2022年2月,完成动画导入原型,版本2.0.0
    2022年3月,辅助工具第3版,添加.hka探索代码,以现在的眼光看,本工具除了有各种缺点,居然还可以,先试着解析
    2022年5月,借助.fbx,.tagxml文件中转比对,完成.hka,.hkx二进制文件解析,.hka支持旋转动画
    2022年5月,支持形态键表情的导入
    2022年5月,dds转png工具改为ImageViewer工具,能完整读取并转换所有的古剑三.dds贴图
    2022年7月,插件第3次重构结束,稳定版本2.5.3,未完成.hka位移动画导入
    2022年7月,修复xml.etree.ElementTree标准库api更改造成的avatar失效的情况
    2022年8月,辅助工具第3版,字节解析,文件对象由python自带的file对象,切换到mmap标准库对象,支持上G文件解析
    2022年12月,完成xac的网格、骨架、形态键表情、碰撞体、多级lod等全部文件内容完整解析与导入
    2022年12月,完成.hka位移数据二进制解析及动画解码
    2023年2月,辅助工具第3版,添加简单的上下文管理函数,极大的简化了探索代码编写量
    2023年3月,完成树木speedtree文件解析(古剑2的.srt,古剑3的.srt文件)
    2023年6月,插件第4次重构出错,硬盘坏了,第4次重构内容消失,仅文件解析部分保留了下来。
    2023年6月,辅助工具第4版,按无膨胀(Bloat-free)图形用户界面设计思路,优化解决了辅助工具非常非常非常缓慢问题
    2023年8月,辅助工具第5版,重构,将极大优化运行速度的显示算法,单独分离出来
    2023年10月,插件第5次重构结束,模型,及.kf,.xsm,.hka动画完整导入


    IP属地:北京22楼2023-10-18 14:41
    回复
      插件的编写,感觉一直在除了在删了重写代码,还是在重写之后又删的路上,现在回想,知道大概的方向,不知道具体的功能,只能是代码写了又删,删了又写,不能用的删除,注释保留关键的错误信息,能用的保留。中间因为没有注释保留关键的探索失败信息,导致不能用的代码,又被我再次编写了出来,调试运行不能用之后,回过头才发现代码怎么好像是前面被我删了的,才意识到自己根本记不住前面那么多错误的探索,只能注释保留关键的探索失败及错误信息,这会让代码文件变得凌乱,但为了不在犯同样的错误,节省时间,只能注释记录的同时,让代码文件变得凌乱些。
      这样删删改改,代码变得面目全非,感觉中重构这么多次就是这么来的,在多次的删写代码之中,慢慢积累能用的函数,函数积累多了,又需要在文件之间多次的剪切粘贴函数代码,这个整理函数的过程,功能不会变化,但函数及代码移动来移动去的整理代码的过程又十分耗费时间,期间想加功能又无法加入进去,十分的麻烦难受。
      就在这删删写写之中,插件有过4次大的停滞不前:


      IP属地:北京23楼2023-10-18 14:42
      回复
        2、2020年8月~2022年1月,接近1年半的时间。
        在8月份的时候,基本把.nif、.xac、.vmesh、.model等模型文件导入blender中,后续一直在想怎么解决动画的导入问题,印象中有3次的集中时间段突击问题,没成功。后续也许是网页搜索引擎变得智能了,我每次搜索,通过搜索1个问题,再点击相关可能的问题,一直集中blender的矩阵动画领域,直到有1天,我在几个英文问答网页来回切换,扫看回答代码,在一次切换网页中,无意中看到了1个函数,突然就意识到了这个函数可能能解决问题,感恩上苍恩赐,如同神赐一般,就这样解决了动画的导入问题,插件也开始了第3次重构
        其实2019年7月开始模型的二进制解析不在是瓶颈后,模型解析过程也一直伴随着动画的解析处理,只是精力主要集中的模型方面,动画则是东一脚,西一脚的简单探探。2020年8月开始全面转向动画二进制解析和动画导入探索后,2020年9月份就定位到了动画解析的关键问题,但实际,这个关键问题的解决也是1年多之后,才如同神赐一般的解决了。
        2020年9月,能有此进度的原因是测试发现,利用blender2.49b,blender29两道中转,能成功的获取到blender29中能正常播放的动画数据并导出为.xml文件,从而能够实现.xsm原文件和blender29中的动画数据一一对应,获得了"标准答案",剩下的就是如何处理原文件数据了。利用这份标准答案成功的导入位置动画,但动画导入失败,经过一系列的比对,最终定位到问题在Armature space(local space) 和 pose space(object space)矩阵居然是有稍微不一样的,这个问题的等价描述是建立edit bone 之前的文件矩阵和建立edit bone后的blender矩阵是不一样的,但他们又十分的相近,且等效,因为没有矩阵数学基础,无法找到这种微妙不同的原因(后续找到了原因是父级y分量的影响),中间一度放下,后面又拿起来,一直查找,一直探索,几次编测试代码,几次删除代码。
        到了2022年1月,动画的导入,就像神的恩赐一样,在按照我自己的思路,尝试到再无思路,在我折腾C++代码转python,思路是对的,代码一一对应是对的,却无正确的结果,其中还有笔者无法处理的矩阵边缘情况,需要再次深入寻找代码,无果的时候。不经意之间,发现不用我自己C++代码转python代码,blender中居然有对应好的python接口,directe, roll = bpy.types.Bone.AxisRollFromMatrix(),之前查看blender文档,有简单的看到过这个函数,但从来没查到和想到,这个函数会是 [文件 bone space] 转[blender edite bone space]的关键。


        IP属地:北京29楼2023-10-18 14:51
        回复
          根据回忆,简单的梳理了下动画导入的矩阵变换:
          在.xsm动画文件二进制解析完成后,开始探索动画的导入逻辑流,期间利用了.xsm的动画数据按.xac骨架的导入逻辑流,成功的导入了有姿势的骨架,虽然不是pose动画,但确认了.xac中的骨架存储数据和.xsm中的动画存储数据,他们的空间是相同的,都是bone space空间数据。只需要将.xsm文件数据 减去 .xac文件数据就能得到basis space数据,插件就能导入动画了,接下来的测试却没有得到正常的结果,很久以后,才知道这个思路是对的,只是减法的对象是错的。
          .xsm文件 bone spcae 数据 不能直接减去.xac文件 bone spcae 数据,而是应该.xsm文件 bone spcae 数据 减去 blender pose bone space数据,这个得到的basis space数据才是能正常播放动画的正确数据。blender pose bone space数据,由【 文件 bone space -> blender editbone local space -> blender editbone bone space = blender pose bone space】得到。
          开始通过使用blender发现,blender basis space空间 与 blender 3d view空间之间存在【 Blender中: 3DView[XZ-Y] == Basis[XYZ], 3DView[XYZ] == Basis[X-ZY] 】坐标系变换,以为会影响到动画的导入,后面测试古剑1和古剑2的.xsm、.kf动画导入,只需要把减出来的basis space数据直接给到blender,不用坐标系变换,动画就能正常播放,说明blender内部已经自动处理了坐标系变换;再后来,测试到.fbx、.hkx和古剑3的.hka动画导入,这个blender内置basis space空间的坐标系变换,确实影响到了动画的导入,导致位置旋转缩放三个通道需要单独的进行坐标系变换,动画播放才能正常。
          ①【文件 bone space】转 【文件 local space,也就是文件world space】。这是matrix的直接转换形式,因为骨骼列表的第1个位置存储的是根节点,所以只需要循环1遍列表,就可以把所有的骨骼的matrix_local全部计算出来,这是1个O(n)的操作。
          for position, [qx, qy, qz, qw], scale, parentid, bonename in filedata.LEKS.骨骼节点列表: 文件骨骼.name = bonename 文件骨骼.parentname = filedata.LEKS.骨骼节点列表[parentid][-1] if parentid != -1 else "" 文件骨骼.matrix_local = mathutils.Matrix.LocRotScale( mathutils.Vector(position), mathutils.Quaternion([qw, qx, qy, qz]), mathutils.Vector(scale) ) if 文件骨骼.parentname == "": continue 父骨骼 = 文件骨架.骨骼字典[文件骨骼.parentname] 文件骨骼.matrix_local = 父骨骼.matrix_local @ 文件骨骼.matrix_local
          这是骨骼建立matrix_local的另一种方式,有兴趣的可以看下:
          for position, [qx, qy, qz, qw], scale, parentid, bonename in filedata.LEKS.骨骼节点列表: 文件骨骼.head_local = mathutils.Vector(position) 文件骨骼.rotation_quaternion_local = mathutils.Quaternion([qw, qx, qy, qz]) if 文件骨骼.父骨骼名称 == "": continue 文件骨骼.head_local = 父骨骼.head_local + 父骨骼.rotation_quaternion_local @ position 文件骨骼.rotation_quaternion_local = 父骨骼.rotation_quaternion_local @ 文件骨骼.rotation_quaternion_local
          ②【文件 local space】转 【blender editbone local space,也就是blender object space】的关键是directe, roll = bpy.types.Bone.AxisRollFromMatrix()代码,(实际上【文件 local space】转 【blender editbone local space】的同时,blender还会自动生成自己的blender editbone bone space数据)
          for 骨骼名称, 文件骨骼 in 文件骨架.骨骼字典.items(): 插件骨骼.name = 文件骨骼.name 插件骨骼.head = 文件骨骼.location direct_local, roll_local = bpy.types.Bone.AxisRollFromMatrix(文件骨骼.rotation_quaternion.to_matrix()) 插件骨骼.tail = 文件骨骼.location + direct_local 插件骨骼.roll = roll_local if 文件骨骼.parentname == "": continue 插件骨骼.parent = 插件骨架.骨骼字典[文件骨骼.parentname]
          ③【blender editbone local space】转 【blender editbone bone space】= [blender pose bone space] 的矩阵是隐藏的,并没有对外展露,后面也是通过网页搜索才找到这个隐藏矩阵的位置分量和旋转分量。
          而【blender editbone local space】转【blender editbone bone space】过程,这个建立editebone同时发生的转换过程,有1个被blender隐藏起来的矩阵,它会生成ebone.head 和ebone.head_local两种数据,而ebone.head的y分量会附加父级骨骼的长度,这也是导致建立edite bone前后,文件 bone space 矩阵数据和blender bone space 矩阵数据2个矩阵数据,数据大概相同,区别很小但与原始文件数据有微妙不一致的根本原因。
          文件local space数据新建骨架editebone过程中的【blender editbone local space】转【blender editbone bone space】这个矩阵是被隐藏起来的,Blender并没有对外展露这个矩阵api。在2018年至2022年期间,Blender是隐藏起来这个矩阵,其api并没有对外展露,也可能是笔者没能查到这个api。笔者C++代码水平较低,属于不到万不得以,不会去查看blender的C++源码,事实证明笔者即使看过blender的armature.c源码,依然没能从C++代码中,找出这个隐藏起来的矩阵,而是靠搜索引擎找到英文网页中国外网友的回答。2023年10月份Blender4.0Beta新版本发布,Blender是否有公开这个矩阵api,笔者未去查询。
          隐藏矩阵的位置分量:
          for pbone in 软件armature.pose.bones: location = mathutils.Vector(pbone.bone.head) if pbone.parent: location.y += pbone.bone.parent.length for time, position in 姿态骨骼.位置帧列表: basis_location = position - location # basis loc
          隐藏矩阵的旋转分量:
          for pbone in 软件armature.pose.bones: rotation_quaternion = pbone.bone.matrix.to_quaternion() for time, quaternion in 姿态骨骼.旋转帧列表: basis_quaternion = rotation_quaternion.conjugated() @ quaternion # basis quat


          IP属地:北京30楼2023-10-18 14:52
          回复
            根据回忆,简单的梳理了下动画导入的探索过程:
            (1)在.xsm动画文件二进制解析完成后,开始探索动画的导入逻辑流,期间利用了.xsm的动画数据按.xac骨架的导入逻辑流,成功的导入了有姿势的骨架,确认了.xac中的骨架存储数据和.xsm中的动画存储数据,他们的空间是相同的,都是bone space空间数据。因此,只需要将.xsm文件数据 减去 .xac文件数据就能得到basis space数据,插件就能导入动画了。接下来的测试却没有得到正常的结果,很久以后,才知道这个思路是对的,只是减法的对象是错的。
            (2)使用blender2.49b和Blender249[Gujian2][xac][xsm][2015-03-02].zip插件,导入古剑2模型及动画并保存.blend文件。后面使用blender29直接打开blender2.49b保存.blend文件,此时blennder29界面会变混乱,不理会,直接保存混乱界面blender29的.blend文件。关闭blender29,重新打开blender29,界面正常,使用blender29追加功能,追加混乱界面保存的blender29的.blend文件里面的collection,这时,神奇的事情发生了,blender29界面显示正常没有变得混乱,模型及动画的播放也正常。
            (3)编写xml导出代码,把blender29里正常的动画数据及相关矩阵数据导出xml,这便获得了标准答案。有了标准答案并与原xsm文件数据进行比较。通过比较,成功导入位置动画,但旋转动画导入出错。basis space动画数据是通过.xsm原文件 减去 .xac原文件得出来,几次测试过后,发现动画位置趋势是对的,但具体的位置数据可能是错的。笔者这时的思路是.xsm原文件 减去 .xac原文件得出basis space动画数据,思路是对的,但减法的对象是错的,真正的减法路径是下一条所讲内容理出来的路径,.xsm bone space 原文件 - (.xac bone space 原文件 -> blender bone space 数据)
            (4)有了标准答案后,把旋转导入过程相关的【edit_bone,pose_bone,bone】的【head, head_local,matrix, matrix_world, matrix_local, matrix_basis,matrix_channel】,测试一遍。最终搞清楚了,.xac新建的edit_bone,是位于local space (armature space or object space),.xsm文件存储的数据位于bone space,bone space 转local space简单,问题出在了【blender local space (armature space)】 转【 pose space(object space)】上,这个矩阵blender29是隐藏的,没有对外暴露。
            由此定位到了动画导入的关键问题,被隐藏起来的矩阵。
            后期通过附加属性的形式,跟踪建立edit_bone的过程,发现edit_bone建立之前和之后的形式是不一样的,笔者用于新建edit_bone的head是1个数据,blender建立edit_bone后,head是另外1个数据。他们是不一样的,但等效。(到了很久后,笔者才理清楚新建editebone和导入动画,其实是【文件local space】 转【blender local space (armature space)】、【blender local space (armature space)】转【 pose bone space】, 和【 pose bone space 】转【 pose local space(object space)】这3个过程)
            (5)继续查找资料,理清bone space 转 basis space 新建location和rotation_quaternion通道动画。对location是减法,对rotation_quaternion是inverted()。
            (6)继续查找资料,找到如何从pose.bone,获取edite_bone的建立后的pose.bone.head。 关键点就是blender里用于姿态的动画的bone会在原始数据的基础上,会在y分量的基础附加父级骨骼长度,才是导致edite bone建立前后数据不一样的根本原因 location.y += pbone.bone.parent.length。这个y分量附加父级骨骼长度得数据 + basis space数据 才真正 = pose space(pose local space)位置数据,同时,网页上得答案,也同样说清楚了pbone.bone.matrix + basis space数据 才真正 = pose space(pose local space)旋转数据,至此导入动画工作流导通,通过查看pbone.bone.matrix数据,发现前面骨架的建立过程,没有给骨骼添加旋转数据。
            (7)通过打印数据测试,理清ebone.matrix 和 pbone.bone.matrix的对应关系,查找blender api并思考出pbone.bone.matrix赋值的edit bone对应的属性是ebone.roll。至此关键矩阵问题的关键节点全部理清。从2020年9月开始发现blender中存在没有提供对外api接口的隐藏矩阵,到找到这个隐藏矩阵的2个分量location = pbone.bone.head,location.y += pbone.bone.parent.length,rotation_quaternion = pbone.bone.matrix.to_quaternion(),耗时长久。
            解决隐藏矩阵的问题后,难点也从姿态导入工作流指向了骨架导入工作流,前面笔者了解到在建立骨架时,笔者并没有给骨骼附加绕骨骼轴向的旋转值ebone.roll。在明白了骨架导入工作流存在的问题后,笔者随之也开始了同样耗时长久的折腾。笔者去查看blender Armature.c的C源码,并转python代码失败,和C++"相同功能"的python代码不起作用,对应的python函数有着笔者无法处理的数学的矩阵边缘情况。继续网页查找,找到了一份blender Armature.c C++源码转python源码,是国外网友已经转好的python函数,复制使用,同样失效不起作用。
            在笔者解决隐藏矩阵问题和骨架导入旋转值这2个问题的历程中,一直尝试到再无思路,在网页搜索查也找不到新的网页时,由于一直无法解决问题,笔者也只好先停下了探索,后面笔者转移了注意力,玩别的内容去了,偶尔想起来后,还是不想放弃的再找找。
            就这样断断续续的想起,在定位到隐藏矩阵问题的1年半后在笔者尝试到再无思路,搜索引擎也找不到新的网页时,在笔者偶尔想起来的再次不死心查找中,点击打开一大堆网页,在一次一次的来回切换网页扫答案的过程中,如同神赐一般,看到了网页回答中directe, roll = bpy.types.Bone.AxisRollFromMatrix()代码,突然就觉得它可能解决问题,感恩上苍恩赐,动画的导入就此得以解决。
            到后续的古剑3动画的解决,其实也走了一小段弯路,好在最终也确定了问题所在,动画.hka/khx文件的通道位置xyz数据,居然是对应的.model文件骨架的-x-y-z位置,按道理它们应该都是xyz,然而.model的骨架数据要变成-x-y-z,动画才能播放正常。


            IP属地:北京31楼2023-10-18 14:54
            回复
              3、2022年5月~2022年12月,接近6个月的时间。
              从动画的导入的问题成功的解决后,插件的重心就开始开始移到全文件支持,在第3次的重构过程中,.xsm虽然有完整代码,所以导入最先解决。接下来是.kf,二进制解析很快也解决,但数据解码出错,后面花费时间,在github上查找nif相关代码,也找到关键的1行代码完成了数据解码。然后就是在2022年5月份的时候,遇到了古剑3动画.hka的二进制解析及data数据块数据解码的难题。
              根据回忆,也简单的梳理了下.hka动画的解析及解码过程:
              (1)最早要从2020年5月份,笔者编译打包的FBXImporterGUI.exe界面工具说起,它的功能就是把.fbx文件转成【.model、.hkx】文件,笔者至今想不起来当时是怎么编译打包成功的,大概怎么做大概清楚,但找不到当时的工程文件了。只记得笔者当时把github上,几乎各个版本的FBXImporter.zip和对应源码都下载下来,最后才编译成功的。
              (2)2022年5月份,笔者遇到了古剑3动画.hka的二进制解析难题,它的难点在于没有任何的字节块大小标识,导致最开始的文件分块都无法进行。最开始是想到查看havok源码,最终也在github上找到源码,查看HavokContentTools部分的源码,确认了是调用的dll,是没有二进制解析的C++源码。随即换了思路,找现成的各个版本的HavokContentTools,把它们都下载遍了,最终找到HavokContentTools_2014-1-0_20140808_64Bit_Anarchy.exe这个版本,能顺利打开.hka文件不报错。然后利用这个HavokContentTools工具把.hka导出为xml文件,这也是获得了另一个意义上的标准答案,根据.xml和.hka文件的一一对应,最终推测出havokint()读取函数和.hka二进制解析结构。这个过程是水磨的功夫,借助github上找到havok的类及其属性,和.xml的实际数据,只能一个类一个类的逐步推进完成二进制.hka文件的完整解析。
              (3)这个时候,在我以为大功告成的时候,类的解析逐步推进到了动画类,然后就遇到data块解码。这个感觉就像什么,就像1个文件里面居然还嵌套了另外的1个文件,这2个文件的结构、思路、风格完成不同。而且.hka虽然能通过HavokContentTools导出为.xml文件,但data数据块在.xml文件中居然保持原样,没有任何变化。只得另寻办法解决。再次到github展开搜索源代码大法,最终找到了旋转动画读取的havokquat()的C#源码,磕磕碰碰的把它化为python函数,经测试能起作用,旋转动画就此解码成功,导入成功。但位移数据的解码依然没能解决。
              (4)在一次回答贴吧网友的帖子中,我提到了我以前编译打包的fbx转model界面工具,我测试了下,.hkx文件映入了我的眼帘中。用我的二进制辅助工具打开看下,哦吼,和.hka一模一样的数据结构。也花费一些时间,完成了.hkx文件的解析,还是遇到了同样的data数据块。为了比较.fbx文件和.hkx文件导入blender中的区别,参考blender3.3自带的fbx导入插件,手写了.fbx骨架及动画解析代码。
              接下来在寻找github代码,看fbx数据,看hkx数据,看fbx通过插件导入blender的情况,看hkx旋转动画导入的情况,用excel统计位置块大小及推测float16、float32个数的可能分布,试图把位置字节大小与数据个数的对应关系找出来。在这些探索事项中来来回回切换,在看github代码看得晃神的时候,在一份我回忆不起来的github代码里,我看到了.hkx位置动画的读取的相似形式的源码,结合我一直统计不出来的位置块字节大小规律,瞬间就发现了位置字节大小与数据个数就是按照源码所示的类似形式对应的,位置数据就这样解码出来了。
              (5)在我高高兴兴解码出来位置数据后,.hkx和.hka的二进制数据都解出来后,导入blender一看,懵了,和blender自带的fbx插件导入的动画怎么不一样。到了这个时候,我开始梳理我自己fbx解析代码,以及.hkx的导入代码,试图找出和blender自带的fbx区别的原因。最后只好去修改blender自带的fbx插件源码,插入测试函数,比较骨架数据,最终找到了错误的原因。(由下方所示3个方面构成)
              ①解码出来的位置数据,.hkx文件和.fbx文件是动画数据是相同的。所以位置通道数据,.hkx文件和.fbx文件在basis space空间都需要进行一次坐标变换,才能和blender自带的fbx插件一致。
              ②havok提供的FBXImporter工具可能有bug,转换出来的Bip001骨骼位置与原fbx文件位置不一致,导致导入blender后,旋转动画也变形了,这时候需要在edit bone编辑模式手动把Bip001骨骼从头顶位置移到中间位置,在导入动画,就正常且一致了。
              ③前面2个解决后,导入古剑3.hka动画还是有问题。测试单个位置通道导入情况,发现骨架“坍缩了”,这意味着basis space空间数据是过小的。当时分析不出结果,后面测试就把以前的胡乱测试,都试了下,把数据不做减法(不做空间转换)直接给到basis space空间,骨架是正常了不“坍缩”了,但没啥动画,我还以为又错了。后面又试了几次,没能理清。后面在写blenderUI界面的时候,在选项设置的代码文件里,在写空间数据处理分发逻辑时,突然才意识到,好家伙,.hka的存储的位置数据和旋转数据,他们的空间居然是不一样的。
              古剑3动画文件.hka存储的位置数据和旋转数据,它们所在空间的不一致的情况,也导致插件进行了第4次重构。2023年1月份开始的第4次重构主要是,将不同文件格式不同代码风格的二进制解析代码统一到相似的形式,二重构插件界面及处理逻辑,适应.hka位置数据和旋转数据空间不同的情形。
              古剑3的.hka动画文件,事件上存在2种不同的动画存储数据空间,hkaInterleavedUncompressedAnimation (位置存储空间是basis space,旋转存储空间是basis space)和hkaSplineCompressedAnimation(位置存储空间是basis space,旋转存储空间是bone space )。由于hkaInterleavedUncompressedAnimation笔者至今只在actor1里找到1份文件是additive_shake_head.hka【1.3m】里找到,为了简化代码的复杂度,对所有的hka文件都按照【位置存储空间是basis space,旋转存储空间是bone space】进行处理,忽略了该份.hka文件对插件的影响。目前,笔者很显然对.hka的文件解析及数据所代表的意义并没有全部理清,但考虑到插件目前基本能覆盖绝大部分古剑3的动画导入,因此对.hka的文件解析及导入告一段落。
              到此,古剑1古剑2古剑3的模型及动画全部梳理清楚,还剩最后的古剑2古剑3的场景地图数据组织形式没有找到,(在第4次重构期间,地图数据的二进制解析已经完成,但这些分块数据,怎么变成完整场景不清楚)。
              时间来到了2023年6月,笔者硬盘崩,第4次重构代码只剩文件解析被保留了下来。


              IP属地:北京32楼2023-10-18 14:55
              回复
                4、2023年8月~2023年10月,接近3个月的时间。
                第5次重构于2023年10份完成,同时也是笔者觉得插件代码已经稳定了下来,后续想加代码,也知道要在什么位置嵌入进去,不会再想去移动代码了。
                在第5次重构期间,笔者遇到了代码组织的问题。怎么描述这个问题呢,就是功能函数的代码是没有变的,也没有新增什么新的功能,但笔者总是觉得这个函数或类放在这里不合适,有时又觉得应该放在另外一份文件里,有时候觉得1个函数应拆成2个函数,就这么来来回回折腾,始终在改变代码里面的工作流。笔者意识到,好像遇到了代码组织问题。解决这个问题,笔者选择了笨办法,就是花费2~3倍的时间,去尝试移动函数到脑海里冒出来的各个位置,这么一通来来回回折腾后,函数功能在哪个文件中,哪个文件是什么命名,函数是什么名称,渐渐的稳定下来。到后面,笔者就觉得整个插件的代码稳定下来了,应该不会再有什么大的函数移动,同时也能兼顾后面可能的场景导入需求。


                IP属地:北京33楼2023-10-18 14:55
                回复
                  大概是体会
                  在这几次的重构过程,最大的体会就是,插件功能有时没有变化,但夹杂着各种探索性质的代码,代码是一直在反反复复的增加修改删除移动,而每增加1个较大的功能,插件就会重复增加修改删除移动代码这个过程,导致代码一直没能稳定下来,各种函数改名,函数移动到其他文件,各种折腾。好在本插件的功能是有界限的,模型导入的网格、骨架、形态键(表情)、权重值、材质、UV、贴图、动画的导入这些内容,场景可能在加1个多文件汇总处理。
                  到今天,插件的代码总算是稳定了,至少笔者不会再想去改函数名,去移动代码到其他文件。想加功能也知道要在哪份文件的哪个位置加。回顾整个插件的编写历程,来总结几个问题的解决脉络,发现是如此的简单清晰,还真是难者不会,会者不难。解决问题,最大的难题,其实是搜索出来所有可能的方向和记录所有尝试的失败,这个过程会耗费巨量的时间和精力,有可以自己忘记了,还会导致再次重复失败的过程,浪费时间,一直搜索,一直尝试,一直测试,却一直没有结果,最是熬人。
                  笔者使用搜索引擎,会尽可能的宽泛,有时就几个关键词,然后一个一个点开页面,看似不相关的页面也会打开查看,看看是否相关,这个会花费大量的时间,然后一直到搜索引擎没有再提供新的结果,再回过头来,分析已有结果,在从搜索页面中,更换几个关键词,再次展开搜索。有时尝试了多个展开后,再开始测试,有时想节省时间,会一边搜索一边测试(事实证明没有节省时间)。
                  这样慢慢的会建立一个记录失败的网格,马后炮来看,成功的路径其实就是挨在一些失败节点的旁边,最后,运气好,回顾整个失败的网格,发现记录失败的网格把成功的路径全包括进来了,而且失败节点旁边就挨着成功路径,只需要再从末端收回路径,就找到了结果。这是1个要看运气的过程,因为这张失败的网格的空间要足够大,才可能把成功路径全包进来,然后再把成功的路径旁边的失败节点也全部包进来。有几次,笔者搜索到了看似无关的问答,想跳过,但担心遗漏信息,最终还是花时间去点开查看,这样才在各种嘎达角落中,找到了各种各样的思路,之后测试,记录失败的情况。
                  关键问题的各个节点,也是通过这样的方式得以推进解决,直至最后一个关键节点的发现,事情就成了。搜索的展开要放到多宽,才是麻烦,这会耗费巨量的时间,这大概是需要运气的,因为并不知道要放大多宽才能把路径全包括进来。有一次笔者的1个矩阵问题,是在一个无关的问答中,看到了解答的作者,举例的一张图中,得到了灵感,解决的。等后面笔者编写完代码,想写引用的时候,却再也找不到那个页面了,笔者自己都忘记了当时通过什么样的搜索路径和跳转路径才找到那个页面的。因为搜索是一个极尽展开的过程,当当查看这些东西,就已经头昏脑胀,一直要持续到搜索再也搜索不到新的信息,才会结束下来,然后回顾搜索结果。在github查找源代码也是一样的。如果能直接搜出答案,那说明问题早已经被解决了。
                  搜索的极尽展开,在花费时间尝试记录整个探索失败的网格点,最后才从末端收回整个路径,运气好,整个探索失败的网格点有把成功路径全包括进来,而为失败节点旁边也挨着成功的路径,就这样运气好,收回路径,事情得以解决,这大概是几次花费大量的时间解决几个难题的体会了。感恩上苍恩赐,插件的代码得以稳定下来。


                  IP属地:北京34楼2023-10-18 14:56
                  回复
                    安装教程
                    日期:2023年10月18日
                    一、简述
                    很早之前,测试过Blender插件的2种安装方式,一种是.zip的半自动安装方式,一种是.rar的手动复制安装方式。这2种的方式的操作数差不多。以前想过,等插件代码稳定下来,提供2种安装方式。当前笔者经过测试后,因本插件的文件名称含有中文名称,使用.zip文件半自动安装,能安装成功,但无法启用插件,因此本存档版本及后续Blender4.0及以上版本将只提供.rar文件。
                    Blender软件自身也有2种安装方式,.exe安装版,和.zip压缩包绿色版。笔者常用的是第2种.zip绿色版的安装方式,原因是笔者有时需要用到好几个版本的Blender,.zip绿色版安装方式对笔者而言更简单。


                    IP属地:北京35楼2023-10-18 14:58
                    回复
                      本插件的.rar的手动安装在升级本插件时出现问题的解决方式如下:
                      (一) .rar的手动安装,安装位置:"D:\Program Files\Blender-3.6.4-windows-x64 \3.6\scripts\addons" 。【其中 "D:\Program Files\" 这部分是你的Blender的安装位置】
                      .rar安装方式:
                      ①右键点击下载的io_scene_烛龙数据.rar,选择“解压到当前文件夹”,会得到一个“io_scene_烛龙数据”文件夹,点击进“io_scene_烛龙数据”文件夹,可以直接看到“__init__.py”文件。
                      如果点击打开“io_scene_烛龙数据”文件夹,直接看到的还是“io_scene_烛龙数据”文件夹,那么里面的这个“io_scene_烛龙数据”文件夹才是插件的文件夹,因为再继续点击打开里面的这个“io_scene_烛龙数据”文件夹,可以直接看到“__init__.py”文件。
                      ②打开Blender,在Blender插件管理器界面,上下滑动找到并点击“导入-导出:烛龙数据”栏,取消勾选,停用插件。
                      ②删除 "D:\Program Files\Blender-3.6.4-windows-x64 \3.6\scripts\addons" 这个文件夹里“io_scene_烛龙数据”文件夹
                      ③复制,新的“io_scene_烛龙数据”文件夹,到"D:\Program Files\Blender-3.6.4- windows-x64\3.6\scripts\addons"文件夹里。
                      ④刷新Blender的插件管理器,也可以关闭Blender再打开Blender。在Blender的插件管理器上,点击“导入-导出:烛龙数据”栏,勾选小方框会显示勾选,启用插件。
                      .rar方式升级插件时,出现问题的解决方式:
                      ①关闭Blender,再打开Blender。打开Blender插件管理器界面,上下滑动找到并点击“导入-导出:烛龙数据”栏,取消勾选,停用插件。
                      ②点击Blender插件管理器界面右上方的刷新按钮。
                      ③刷新后,继续在Blender的插件管理器上,点击“导入-导出:烛龙数据”栏,勾选小方框会显示勾选,启用插件。
                      升级本插件时,出现的问题就此解决。


                      IP属地:北京36楼2023-10-18 15:00
                      回复
                        近年插件开发过程中,笔者经常在Blender3.3,Blender3.6,偶尔Blender3.0之前来回切换【Blender3.6用于开发插件,Blender3.3用于查看BlenderUI代码】,.zip的半自动安装方式,在安装及更新插件时出现了问题。解决插件升级出现的问题,经常需要在Blender的插件管理页面,先点选停用,在手动删除旧的插件文件夹,在重新复制新的插件文件夹进去,再在Blender的插件管理页面启用插件。这个过程和手动安装方式一模一样。随着Blender4.0的发布,Blender4.0也难以避免的再次遇到兼容问题,插件也必须跟着分成新旧2条插件维护线【原本只需要1条维护线就行】。所以为了减少以后升级插件可能遇到的问题,Blender4.0及以后的版本将只提供.rar的安装方式。


                        IP属地:北京37楼2023-10-18 15:00
                        回复
                          一、Blender绿色版安装教程及插件安装教程
                          (1)打开Blender官网,http://www.Blender.org

                          (2)点击Download,接着点击Download页面中间的下拉箭头,点击”“Windows Portable (.zip)版本(绿色版)下载,等待下载完成。



                          (3)等下载完成后,可以选右键解压到当前文件夹,得到“Blender-3.6.4-windows -x64”文件夹,再把这个文件夹,复制或移动到你想放它的位置,就安装好绿色版了。
                          Win11操作系统的话,可以直接点击Blender-3.6.4-windows-x64.zip文件,再把里面的“Blender-3.6.4-windows-x64”文件夹,拖到你想放的位置。

                          笔者常用有Blender3.3和Blender3.6,所以文件夹里会有2个Blender安装文件夹。



                          IP属地:北京38楼2023-10-18 15:04
                          回复
                            笔者下面以Blender-3.6.4-windows-x64版本为例,介绍插件的手动安装方式,其他版本的Blender也是同样的方式,复制一份文件夹进去,这个各个版本的插件不会相互影响,出现各种升级问题。
                            (4)下载io_scene_烛龙数据插件,(不需要提取码,网址可以直接打开)
                            插件下载地址:https://pan.baidu.com/s/100Mns8a6eLguL19pwPfv9g


                            下载 io_scene_烛龙数据V2.6.4_Blender3.3.0-3.6.4.rar 文件下来,就行。
                            插件当前最低支持Blender3.3版本,最高支持Blender3.6版本。Blender4.0版本及以上,材质导入大概率出错。
                            (5)右键,解压到当前文件夹,得到“io_scene_烛龙数据”文件夹,注意点击进去,可以看到“__init__.py”文件
                            ①右键,解压到当前文件夹

                            ②得到“io_scene_烛龙数据”文件夹

                            ③点击打开得到“io_scene_烛龙数据”文件夹,可以看到“__init__.py”文件,说明“io_scene_烛龙数据”文件夹就是本插件的文件夹。

                            (6)把解压得到的“io_scene_烛龙数据”文件夹,复制到Blender的绿色版的安装位置的blender内置插件文件夹(区别于Blender的C盘user插件安装文件夹)。

                            在Blender安装位置的安装好了插件文件夹如下图

                            这样就是复制好了,本插件到Blender的安装位置的内置插件管理文件夹里了,后面就是Blender软件中的插件管理界面点选插件了。 【前面路径中的 "D:\Program_ operations\" 便是前面我刚刚放置Blender的.zip绿色版版的安装位置】。


                            IP属地:北京39楼2023-10-18 15:10
                            回复
                              (7)在Blender的插件管理器界面上,点击“导入-导出:烛龙数据”栏,勾选小方框会显示勾选,启用插件,(之后记得保存设置;一般会自动保存,不需要手动保存)。






                              IP属地:北京40楼2023-10-18 15:12
                              回复