关于一个2D UI引擎的效率提升问题

winnuke 2010-09-08 09:37:58
这个利用D3D实现的UI引擎是基于层的一个设计。一个窗口是一个层,而且这个窗口可以拥有子层,比如按钮,比如EditBox。在内部实现上一个层对应一个Texture,并且拥有父亲层和子层。如果一个子层的内容发生了变化,他首先做的就是把他的绘制内容重绘一遍(通过Sprite绘制图像和文字等),然后再把所有的2级子层的Texture绘制到自己身上,然后对父亲层逐级向上递归调用这个方法。直到最上面的root层(这里可以把所有层想象成一个树状结构),然后把root层的纹理通过Sprite绘制到D3D窗口。

这就导致一个小小的按钮控件的刷新会导致所有的父亲层重绘。尽管我加入了裁剪机制,效果还是不太理想,请各位帮忙想象有什么可以改进的。
...全文
495 18 打赏 收藏 转发到动态 举报
写回复
用AI写文章
18 条回复
切换为时间正序
请发表友善的回复…
发表回复
dinoui 2011-02-12
  • 打赏
  • 举报
回复
你可以使用dinoUI界面引擎,它比用CEGUI来开发界面,相同的功能,能减少大约3/4的程序代码量,能减少20~30个人月的研发时间。它比CEGUI的效率要高至少一倍。
你可以上这个网址了解一下:http://www.dinoui.com

winnuke 2011-01-22
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 lymastee 的回复:]

用Sprite实现的?如果一个窗口的某部分可以任意变大小你怎么实现?我想看看你的代码不知可以不.我通常是直接用Texture画.

你可以尝试把所有窗口控件分离开,不要用什么层次模型,然后用Z-order来处理互相遮盖,建立一个BackBuffer swapchain,然后利用pDevice->Present()中可以指定刷新矩形的功能把窗口有变化的那部分直接画到backbuffer上去.
……
[/Quote]

谢谢。
目前取消了缓存机制,绘制的时候,从最底层开始绘制,并进行适当的裁剪,效率上去不少。
zlc53 2011-01-14
  • 打赏
  • 举报
回复
UI引擎?别什么都叫引擎好不

UI只是简单搞几个窗口,按钮,当然很简单,你要想写一个大而强的UI,那复杂度不会亚于任何一个3D引擎。
xychzh 2011-01-14
  • 打赏
  • 举报
回复
[Quote=引用 15 楼 zlc53 的回复:]
UI引擎?别什么都叫引擎好不

UI只是简单搞几个窗口,按钮,当然很简单,你要想写一个大而强的UI,那复杂度不会亚于任何一个3D引擎。
[/Quote]

CEGUI就是个例子。
gameatp 2010-12-31
  • 打赏
  • 举报
回复
一般思路就是,创建一个大的顶点缓存,使用大纹理,分窗口渲染
raphaelcheung 2010-09-27
  • 打赏
  • 举报
回复
如果你的页面层数比较多,
那么建议不要每个控件都弄个缓冲层
比方说一个控件可以容纳子控件但是不需要对子控件进行裁剪,那么他就不需要一个缓冲区
还有像button radio之类的控件也没有必要做成容器那样的
每个控件都加个缓冲区虽然编码方便,但是缓冲区多了对效率的影响是数量级的,这个很容易计算出来
地球之子 2010-09-24
  • 打赏
  • 举报
回复
告诉你个小秘密:ID3DXSprite::Draw()这个函数并不绘制任何Texture,而是登记一个绘制流程而已,所有的Texture都是ID3DXSprite::End()绘制的。

如果存在效率问题,通常不是Sprite造成的(除非你调用ID3DXSprite::Begin()的时候用错了参数)。你也没必要使用裁剪,因为每张Texture只是贴在4个顶点的矩形上,这开销相对于任何一个模型而言,都微不足道。你应该多检查一下你的分层算法。
lizelglglg 2010-09-23
  • 打赏
  • 举报
回复
我以前也写过UI,我是通过directdraw软实现的,后台缓冲保存整个屏幕的样子,然后每一个texture保存自身的样子(当时只是为了很多特效才这么做的),画的时候只需要把重绘部分拷贝到后台缓冲去,然后我还保存了该窗口遮挡住的的图像,窗口隐藏则还原遮挡部分(因为每一个窗口样子五花八门,直接像windows一样涂几个颜色重绘根本不可能,而且还有透明窗口,如果让下面的所有窗口重绘该区域速度会很慢)也可以模仿windows画边框归画边框,填充内部归填充内部,windows窗口不透明好实现得多
如果你已经设计得太深入了,而且还是那种某一窗口导致N级重画,我觉得还不如重写。
Pro_X 2010-09-23
  • 打赏
  • 举报
回复
UI引擎?别什么都叫引擎好不
yashuwa0622 2010-09-23
  • 打赏
  • 举报
回复
说实话,我是很不喜欢用DX的sprite功能,貌似系统兼容性不太好
diaoni 2010-09-19
  • 打赏
  • 举报
回复
UI更多的是资源管理(纹理,字体等等),消息机制,控件逻辑,以现在硬件的能力,渲染不会构成瓶颈
diaoni 2010-09-19
  • 打赏
  • 举报
回复
3D下,以前的2D绘制技术很多都不适用了,诸如脏矩形之类的优化是多余的

在绘制阶段,所有的窗口都应该转化为vertex+texture,保存在vertex buffer中,然后提交给GPU。遮挡在遍历窗口树的时候可以获得正确的绘制顺序。更进一步的优化涉及到怎样组织窗口的vertex数据(哪些窗口应该放到同一个VB中),只有在窗口内容改变的时候才修改VB的内容等。

CEGUI是不错的参考:)
LL1027973141 2010-09-17
  • 打赏
  • 举报
回复
你可以打开工具数据库源代码,进行修改,这就需要编程知识了 0.0....
zhangshoucheng 2010-09-17
  • 打赏
  • 举报
回复
我认为你可以使用脏矩形进行描绘,效率能提升不少。不过也是从最下面画到最上面。这种方法我们用过,很理想。
winnuke 2010-09-08
  • 打赏
  • 举报
回复
[Quote=引用 1 楼 lymastee 的回复:]

用Sprite实现的?如果一个窗口的某部分可以任意变大小你怎么实现?我想看看你的代码不知可以不.我通常是直接用Texture画.

你可以尝试把所有窗口控件分离开,不要用什么层次模型,然后用Z-order来处理互相遮盖,建立一个BackBuffer swapchain,然后利用pDevice->Present()中可以指定刷新矩形的功能把窗口有变化的那部分直接画到backbuffer上去.
……
[/Quote]
任意改变大小很难做到,一般就是创建的时候创建大一点的Texture,然后绘制的时候用透明色来处理窗口大小。

不用层次模型的话现在改动可能会比较大,这个工期上的开销不知道能否接受。

如果按照现有层的概念来改进,有没有什么显著一点的方案呢?
lymastee 2010-09-08
  • 打赏
  • 举报
回复
用Sprite实现的?如果一个窗口的某部分可以任意变大小你怎么实现?我想看看你的代码不知可以不.我通常是直接用Texture画.

你可以尝试把所有窗口控件分离开,不要用什么层次模型,然后用Z-order来处理互相遮盖,建立一个BackBuffer swapchain,然后利用pDevice->Present()中可以指定刷新矩形的功能把窗口有变化的那部分直接画到backbuffer上去.

如果仿照WIN32那种窗口结构要想在性能上有突破有点困难,毕竟D3D画画不需要什么DC,但如果不用层次模型,可能在处理鼠标和键盘事件的时候会有点麻烦.你可以尝试用一棵红黑树来存储窗口的指针,这样每当发生位置改变时,最多只要3次旋转操作就能复位
gamemagic 2010-09-08
  • 打赏
  • 举报
回复
层次模型也不是不可。

不过要尽量做到最小改动,即使一点小的变化也需要重新绘制所有的内容。

比如,只有一个按钮按下了,需要改变上面的图像,

这时你可以锁定顶点缓冲的需要改的部位,然后修改对应的纹理坐标

然后重新绘制。

需要注意的是:所有的UI图片都应该放在同一张texture里,创建VB时需要指定Pool Dynamic和Usage Default

还有就是锁定Vb时的参数,一般需要No overwrite和Discard
lymastee 2010-09-08
  • 打赏
  • 举报
回复
这个恐怕比较困难了,

D3D里最耗时间的是分配内存和Draw,如果想用尽量小的改动去改进的话,就细节上尽量少Draw,尽量减少Draw的面积,但按照层次模型来看的话,确定要绘制的区域估计开销会很大

8,301

社区成员

发帖
与我相关
我的任务
社区描述
游戏开发相关内容讨论专区
社区管理员
  • 游戏开发
  • 呆呆敲代码的小Y
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧