TA的每日心情 | 慵懒 2015-1-8 08:46 |
---|
签到天数: 2 天 连续签到: 1 天 [LV.1]测试小兵
|
今天使用Ogre, 居然接连遇到了Ogre的几个Bug, 首先我声明我使用的Ogre1.2版本, 也许这些我所谓的Bug在1.4版本中已经修正了.
1. Entity::setVisible() 无效
平常使用setVisible() 总是屡试不爽, 感觉没有什么问题, 今天突然发现 setVisible() 居然无效了, 后来又发现对于有的Entity是有效的, 有的又无效了, 郁闷了半天. 后来发现只要Entity使用了非固定管线的材质(Shader), 其setVisible就没有作用了, 汗一个, 典型是那个Fresnel反射的水面, 无法通过setVisible()隐藏掉, 后来我使用SceneNode::detachObject()代替了. 再汗一个.
2. Root::removeFrameListener() 无效
与上面那个Bug相比, 这个Bug更让人匪夷所思, 并不是说removeFrameListener不起作用, 它却是在下一桢内才真正把这个Listener删除掉, 这一桢内却是还是正常的回调.
这样对于这样一个结构的代码, 就有个致命的问题了(我自己认为我的这个代码构架很不错)
比如有这样一个对象, 需要每桢动态Update自己的数据, 于是我使用了FrameListener
class Object : public FrameListener
{
Object();
~Object();
bool frameStarted(const FrameEvent& evt);
}
当然我在构造的时候, 讲自己注册为FrameListener , 因为自己本身就是FrameListener
Object::Object()
{
Root::getSingleton().addFrameListener(this);
}
这段代码工作的很好, 加入以后函数里面的frameStarted()每桢都会被回调了, 这没有问题.
关键是销毁的时候, 当然同理, 在我们销毁Object对象的时候, 我们要removeFrameListener, 这看似理所当然的东西,在运行的时候却出现了致命的错误.
我们的析构函数如下:
Object::~Object()
{
Root::getSingleton().removeFrameListener(this);
}
看上去很完美吧? 其实当你销毁这个对象的时候是一定会出错的. 因为Ogre是下一桢才真正Remove掉的, 这一桢还是要照常执行这个回调的, 不信的话就去瞧SourceCode, 但是当这个析构执行完后, this的只个对象就消失了, Ogre保存的FrameListener其实是一堆垃圾, 他一调用当然就错了啊.
后来, 没有办法, 加了一行臭代码, 解决了这个问题, 但始终觉得很恶心.
Object::~Object()
{
Root::getSingleton().removeFrameListener(this);
Root::getSingleton().renderOneFrame(); //跳一桢真正Remove掉FrameListener
}
3. 虽然物体隐藏了, 但渲染到纹理的过程仍然在继续
比如当我渲染Rtt的水, 当我把水面的Entity隐藏了,本以为其Rtt过程会自动停止,其实不然,它仍然在默默的渲染着,一刻都不停息过,这个问题是我用NVPerfHUD检查的时候发现的.其实仔细想想,也不能算他是个Bug吧, Ogre也没有义务在你隐藏Entity时候自动关闭Rtt. 所以我建议大家使用Rtt的时候,不要使用AutoUpdate(),那样是不好控制的,
使用手动Update,在FrameListener中根据当前物体的显示和隐藏情况自动决定是否要更新RenderTexture.
感觉这几个bug都有些难以理解, 尤其最后一个, 要多加小心, 因为他很难被发现, 又白白的浪费的性能. |
|