引擎设计跟踪(九.14.3.4) mile stone 2 - model和fbx导入的补漏

时间:2022-09-17 19:36:54

之前milestone2已经做完的工作, 现在趁有时间记下笔记.

1.设计

这里是指兼容3ds max导出/fbx格式转换等等一系列工作的设计.

最开始, Blade的3dsmax导出插件, 全部代码都是写在导出的DLL里面的, 后来考虑到FBX等等其他格式, 现在把模块分成两部分:

  • Model/Anim Collector: 预定义的接口, 用于收集其他模型的相关数据. 用户负责扩展实现, 比如FBXCollector, MaxCollector, 或者其他格式.
  • Model/Anim Builder: 负责调用Model Collector的预定义接口来生成Blade的Mesh, 内置在Model插件中并提供接口.

导入/导出之类的也自然分为两个phase:

collecting data => building mesh

这么做的好处是builidng mesh/animation的代码全部可以复用, 而且building mesh的代码和复杂度才是最大的. 由于model builder内置到model模块内部, 只要根据工厂创建出内置的对象就可以了, 这有点像Java的风格.

而collecting data作为用户可扩展的方式, 只要有定义良好的接口, 就可以只实现model collector, 主要是使用三方SDK获取数据, 工作量相对要小很多.

2.编辑器导入插件

对于编辑器来说, 设计的思路是可以直接打开FBX文件. 比如像photoshop和3ds max这样的软件, 如果安装了文件格式的插件, 就能支持打开对应格式文件.

之前Blade对于"文件导入"没有任何抽象, 于是添加了下面的接口:

     struct SEditorImporterInfo
{
enum
{
IMPORTER_ID_TAG = 0x80000000,
};
TString mName; ///factory class
TString mTarget; ///target IEditorFile type
TString mTargetExt; ///target file extension
TStringList mExtensions; ///supported extensions
//importer type: assigned by framework
FileTypeID mTypeID; ///importer type IDs are in the same space of editor file type ids
///FileTypeID with IMPORTER_ID_TAG represent a importer.
IconIndex mIconID; inline bool operator<(const SEditorImporterInfo& rhs) const {return mName < rhs.mName;}
static inline bool comparePtr(const SEditorImporterInfo* lhs, const SEditorImporterInfo* rhs) {return *lhs < *rhs;}
}; class BLADE_EDITOR_API IImporter : public TempAllocatable
{
public:
virtual ~IImporter() {} /**
@describe get the factory class name of the importer,
corresponding to SEditorImporterInfo::mName
@param
@return
*/
virtual const TString& getName() const = ; /**
@describe
@param source: input source file stream that importer can support
@param dest: output converted/imported format recognized by framework & plugins
@param params: extra parameters used for importing
@param extraFiles: extra file created by importer. extra files can only contains file names, files should be created at the same path/folder of input source file.
@param callback: callback for importing progress
@return
*/
virtual bool import(const HSTREAM& source, const HSTREAM& dest, const TParamList& params, TStringParam& extraFiles, CallbackRef& callback) = ;
}; extern template class BLADE_EDITOR_API Factory<IImporter>;
typedef Factory<IImporter> ImporterFactory;

导入信息记录了: 支持的源文件格式(扩展名), 目标格式. 也就是说, 导入器并不提供文件格式的解析(不会根据文件内容来创建任何编辑器对象), 只是单纯的转换成(其他插件)已经支持的其他格式.

这样以来, "导出"实际上做的事情就是格式转换. 比如FBX导入插件, 是使用FBXCollector和IModelBuilder, 生成Mesh(blm)文件到一个stream里面, 而blm文件已经有插件可以将它打开了.

在编辑器使用的时候, 可以直接拿memory stream作为dest stream, 通过导入器fbx文件完成格式转换, 然后在根据导入信息里面的"目标格式", 用工厂创建真正要打开的文件实例来打开转换后的stream; 等打开成功以后, 删除掉memory stream/memory file system里面的文件(临时mesh文件).

3.批量格式转换(CLI)

由于fbx文件的转换代码全部在编辑器的fbx importer插件里面, 为了模块复用, 这里的model converter工具实际上是手动加载了fbx importer插件, 跳过编辑器的管线, 直接调用import接口完成文件格式转换.

同时, 添加了makefile来支持批量的fbx转换.

问题1: 模型/骨骼/动画合并

这个是跟具体项目的spec相关的, 很多项目的动画文件是拆分成单个clip的, 每个动画对应一个源文件. 有的是单个文件包含所有的动画.

blade的model converter 支持多个源文件合并, 为了makefile能够方便处理, 只要将一组动画/模型放入同一个子文件夹, makefile会拿到所有文件列表并调用converter来合并出最终的模型和动画.

对于runtime, 实际项目中, 有的商业引擎没有很好的处理和优化, 导致一个角色的所有不同的装备对应的所有骨骼, 都会参与骨骼计算, 实际上有很多是无效的 - 没有任何绑定. 而且有的引擎, 实际上想做针对性的优化, 也很难下手, 改动比较大. 因为实际项目中遇到过类似的情况, 所以Blade以及提前考虑并做了处理: 只有在runtime具有有效绑定mesh的骨骼才参与动画计算, 否则忽略.

问题2: 集成到工程

这个问题和以前的tex compressor一样, 把makefile集成到工程, 并且把max文件转换成fbx放入库里作为源文件, 实现一键构建, 具体怎么做不再记录了.

由于现在的测试资源越来越多, 所以工程上也把美术资源和代码分开, 单独放到一个repo里面去.

使用fbx的另外一个好处就是, 调试和改进mesh的导入/导出, 都可以不依赖3ds max了.

其他

submesh的bounding计算

在google上查到的最好方式, 是根据模型的绑定信息, 生成对应骨骼的包围. 注意所有绑定信息都在模型上面, 只要拿到对应骨骼id所有的顶点, 就可以计算出包围盒; 不需要骨骼/动画文件的任何信息.

所以包围盒可以只根据模型文件离线生成. 之后runtime更新时, 再根据骨骼动画来变换包围盒.

包围盒更新和可见性依赖

Blade的动画流程大致如下: 如果模型不可见, 那么就不会更新动画, submesh的包围盒就不用更新.

这里有一个死结, 就是模型的可见性本身也依赖包围盒, 如果不更新骨骼动画和包围盒, 就可能影响可见性.

目前解决方案是: 拿模型的静态包围盒做粗略的视锥剔除

  • 如果全部可见, 就不更新包围盒, 只更新骨骼动画, 虽然这个时候可能会有不可见的submesh没有更新到, 但是影响不大只会有一点overdraw.
  • 如果部分可见, 那么就更新骨骼动画, 并根据LOD信息选择性的更行submesh的包围盒, 做更细粒度的剔除.
  • 如果不可见, 那么就不更新动画和包围盒. 这里有一个前提就是模型的静态粗略的包围盒要足够大, 否则会影响视觉, 导致动画中的submesh本来可见, 但是模型的粗略视锥剔除导致其不可见.

动画LOD

由于远处的物体本身就比较小, 所以可以不更新包围盒. 这个可以通过骨骼动画的LOD来调整.

LOD的计算并非是根据距离, 实际上应该根据屏幕上投影后的大小来, 因为远处的动画可能很大, 未必就应该忽略.

而骨骼动画的计算频率也不需要满帧计算, 记得之前提到过, 30FPS已经到达人眼的识别上限, 实际上大部分电影24FPS就足够, 但游戏有很多不同http://www.zhihu.com/question/21081976, 而且现代电影都是48FPS, 有两帧一样的画面来组成.

目前Blade会根据投影后的尺寸来调整骨骼动画计算频率, 比如较远/较小的动画就会用低频更新, 最高频率也不会是满帧, 而是大约66FPS.

引擎设计跟踪(九.14.3.4) mile stone 2 - model和fbx导入的补漏的更多相关文章

  1. 引擎设计跟踪&lpar;九&period;14&period;2a&rpar; 导出插件问题修复和 Tangent Space 裂缝修复

    由于工作很忙, 近半年的业余时间没空搞了, 不过工作马上忙完了, 趁十一有时间修了一些小问题. 这次更新跟骨骼动画无关, 修复了一个之前的, 关于tangent space裂缝的问题: 引擎设计跟踪( ...

  2. 引擎设计跟踪&lpar;九&period;14&period;2 final&rpar; Inverse Kinematics&colon; CCD 在Blade中的实现

    因为工作忙, 好久没有记笔记了, 但是有时候发现还得翻以前的笔记去看, 所以还是尽量记下来备忘. 关于IK, 读了一些paper, 觉得之前翻译的那篇, welman的paper (http://gr ...

  3. 引擎设计跟踪&lpar;九&period;14&period;2h&rpar; 开发计划

    以后的开发计划: 完善game runtime code, 跑简单的demo目前只有编辑器的运行流程, 没有游戏/demo流程, 图形的测试主要在编辑器上测试, 现在需要测试android系统的图形, ...

  4. 引擎设计跟踪&lpar;九&period;14&period;2i&rpar; Android GLES 3&period;0 完善

    最近把渲染设备对应的GLES的API填上了. 主要有IRenderDevice/IShader/ITexture/IGraphicsResourceManager/IIndexBuffer/IVert ...

  5. 引擎设计跟踪&lpar;九&period;14&period;2g&rpar; 将GNUMake集成到Visual Studio

    最近在做纹理压缩工具, 以及数据包的生成. shader编译已经在vs工程里面了, 使用custom build tool, build命令是调用BladeShaderComplier, 并且每个文件 ...

  6. 引擎设计跟踪&lpar;九&period;14&period;2f&rpar; 最近更新&colon; OpenGL ES &amp&semi; tools

    之前骨骼动画的IK暂时放一放, 最近在搞GLES的实现. 之前除了GLES没有实现, Android的代码移植已经完毕: [原]跨平台编程注意事项(三): window 到 android 的 移植 ...

  7. 引擎设计跟踪&lpar;九&period;14&period;2d&rpar; &lbrack;翻译&rsqb; shader的跨平台方案之2014

    Origin: http://aras-p.info/blog/2014/03/28/cross-platform-shaders-in-2014/ 简译 translation: 作者在2012年写 ...

  8. 引擎设计跟踪&lpar;九&period;14&period;2j&rpar; TableView工具填坑以及多国语言

    Blade的UI都是预定义的接口, 然后由插件来负责实现, 目前只有MFC的插件. 最近加上了TableView的视图, 用于一些文件的查看和编辑, 比如前面在文件包的笔记中提到需写一个package ...

  9. 引擎设计跟踪&lpar;九&period;14&period;2b&rpar; 骨骼动画基本完成

    首先贴一个介绍max的sdk和骨骼动画的文章, 虽然很早的文章, 但是很有用, 感谢前辈们的贡献: 3Ds MAX骨骼动画导出插件编写 1.Dual Quaternion 关于Dual Quatern ...

随机推荐

  1. 【转】swift实现ios类似微信输入框跟随键盘弹出的效果

    swift实现ios类似微信输入框跟随键盘弹出的效果 为什么要做这个效果 在聊天app,例如微信中,你会注意到一个效果,就是在你点击输入框时输入框会跟随键盘一起向上弹出,当你点击其他地方时,输入框又会 ...

  2. PL&sol;pgSQL的 RETURN NEXT例子

    从网上找到例子: 可以说,RETURN NEXT要用在循环中: 例子一: 数据准备: CREATE TABLE foo (fooid INT, foosubid INT, fooname TEXT); ...

  3. JQuery(下)

    26.jQuery 中的 DOM 操作 )DOM(Document Object Model—文档对象模型):一种与浏览器, 平台, 语言无关的接口, 使用该接口可以轻松地访问页面中所有的标准组件 ) ...

  4. 一看就能学会的H5视频推流方案

    本文由云+社区发表 作者:周超 导语 随着直播平台爆发式增长,直播平台从 PC 端转战移动端,紧跟着直播的潮流,自己学习实现了一套简单的 H5 视频推流的解决方案,下面就给小伙伴们分享一下自己学习过程 ...

  5. Scrapy 隐含 bug&colon; 强制关闭爬虫后从 requests&period;queue 读取的已保存 request 数量可能有误

    问题描述和解决方案已提交至 Scrapy issues: The size of requests.queue may be wrong when resuming crawl from unclea ...

  6. MySQL学习&lpar;四&rpar;

    1 MySQL日期和时间类型 创建一个包含DATE类型的表 mysql> create table test3( -> star varchar(20) not null default ...

  7. java面试:手写代码

    二分查找法. /** * 二分查找法:给定一组有序的数组,每次都从一半中查找.直到找到要求的数据. * 主要是得找到下标的表示方法. */ public class BinaryFind { /** ...

  8. 全网数据实时备份方案&lbrack;inotify&comma;sersync&rsqb;

    环境搭建 0.环境安装   gcc  yum install gcc -y 1.安装inotify(源码软件包) 文件下载:https://files.cnblogs.com/files/ftl101 ...

  9. 《自己动手写docker》之namespace部门实验

    动手写一遍,印象不一样! package main import ( "log" "os" "os/exec" "syscall& ...

  10. unity 3D &plus; Google Play In-app Billing &lpar;IAB&rpar;&lpar;转&rpar; 热度 3

    最近由于工作需要,研究unity如何接入Google Play以实现游戏内购买.目前IAB的实现,prime31做的插件比较好,各平台的IAB均有,但费用相对过高(几乎都是70刀左右,可怜穷小子).在 ...