51Testing软件测试论坛

 找回密码
 (注-册)加入51Testing

QQ登录

只需一步,快速开始

微信登录,快人一步

手机号码,快捷登录

查看: 2221|回复: 0
打印 上一主题 下一主题

3D引擎中的异步资源调入

[复制链接]
  • TA的每日心情
    慵懒
    2015-1-8 08:46
  • 签到天数: 2 天

    连续签到: 1 天

    [LV.1]测试小兵

    跳转到指定楼层
    1#
    发表于 2008-1-9 11:26:00 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
    前几天又和一个朋友谈到连续世界(Continuous World)的实现,他讲“这很简单,后台使用一个线程读磁盘不就行了”。这使我想起F3D中的异步资源调入机制,这是F3D中我最不满意的一个部分(请见之前的博文:)。
    F3D中的异步资源调入就是基于这种直觉去设计的,设计目标是:不单场景可以异步调入,道具模型,角色模型等都需要异步调入,这主要是为了避免游戏逻辑被卡在读盘上,造成某些操作的时候会卡一下。所以,F3D的异步资源调入机制是建立在Resource基类上的,这样所有的Resource都可以使用异步调入机制。实现也很简单:
    1.启动一个线程(且叫它IO线程),它开始等待一个event;
    2.主线程将需要调入的资源加入一个队列中,并激活这个event;
    3.IO线程被激活,它开始循环读取请求队列,完成所有IO请求,然后回到1的状态。 这个方案缺乏设计,主要体现在两个方面,首先是异步资源调入机制对上层逻辑的影响考虑不足,其次是没有考虑资源自身也有内在联系。

    先从简单的说起,看看后者:资源自身的内在联系。例如一个角色模型--在F3D中是一个Resource的派生类--ResSkin,当这个资源被载入成功之后,现有的机制是,当渲染系统引用材质的时候,会发现贴图资源(是另外一个Resource的派生类ResTexture)还没有创建,则会将贴图读取请求发送给IO线程,而当前帧则只能使用一个默认材质,这样造成的结果就是角色模型会显示成白色,最坏的情况是:如果IO请求队列中已经有了很多其他请求,那么这个“空白材质”的状态会十分显眼。另外一个资源相关的例子在游戏层,例如一个主角,因为要换装,可能需要几个skin来组成,理想的情况下是需要这些skin全都加载完成之后,才显示出来。
    再来看一下对上层逻辑的影响。为了举例子,先交代一下F3D的Entity,Entity包括一个Resource对象引用和一个AnimCtrl对象,前者指向对象资源,后者用来存储动画播放的动态,以及控制逻辑,这是一个典型的FlyWeight模式。如果没有引入异步IO的情况,那么很简单:
    Entity* myChar = new Entity;
    myChar->LoadResource("asdf.xxx");
    myChar->PlayAnim("walk");
    引入了异步IO之后,有一个问题就要处理了,LoadResource()调用之后,资源并没有立即可用,AnimCtrl无法知道资源中是否有walk动画,也不知道这个动画有多少关键帧,无法立即执行PlayAnim()的操作!如果把这个问题封装在AnimCtrl这一层,即把PlayAnim()命令存储起来或者开始累计动画时间,并每帧检测资源是否创建完成,一旦完成则将动画状态计算好。这显然是一种很傻的办法,而且上层相当于一个busy loop的模式,效率很低!
    要解决这两个问题,方法之一就是,所有有关上层逻辑的资源对象都不使用异步IO机制,即只有World Geometry才使用异步IO。这样大大简化了问题。
    我一直在思索如何真正解决这两个问题...。对于资源之间的联系,我想还是比较好解决的,只要加入一个“IO请求分组”的概念即可,对于模型引用贴图这种情况,可以为Resource增加一个方法用来获得某资源内部引用了那些其他资源,这样在IO线程中,某资源调入完成之后,递归的调入其引用的所有资源;至于主角换装系统那种游戏层的需要,就只能提供接口,由逻辑层来完成“提交一组IO请求”的功能。
    “IO请求分组”这一个概念无法孤立的工作,必须配合“完成通知机制”。如果想要避免busy loop模式(上层每帧都去问,资源调入了没有?),那就只有引入“完成通知机制”了,这也就意味着异步IO模型带来的异步编程的复杂性,无法完全封装在底层,必须由上层承担。上层在添加一个IO请求的时候,可以指定一个事件信息的结构体,当IO线程完成该IO请求的时候,通知主线程,并同时携带此事件信息,其面Entity的例子就变成了:
    Event initAnim(...);
    Entity* myChar = new Entity;
    myChar->LoadResource("asdf.xxx",initAnim);
    ....
    void onInitAnim()
    {
      myChar->PlayAnim("walk");
    }
    这种编程方法给上层增加了很大的复杂度,也不是一个很理想的方法。如果您想到什么更好的思路,请一定告诉我啊。:)
    分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
    收藏收藏
    回复

    使用道具 举报

    本版积分规则

    关闭

    站长推荐上一条 /1 下一条

    小黑屋|手机版|Archiver|51Testing软件测试网 ( 沪ICP备05003035号 关于我们

    GMT+8, 2024-11-16 06:23 , Processed in 0.069293 second(s), 27 queries .

    Powered by Discuz! X3.2

    © 2001-2024 Comsenz Inc.

    快速回复 返回顶部 返回列表