C# XNA 2D 轨迹效果优化 [英] C# XNA 2D trail effect optimization

查看:27
本文介绍了C# XNA 2D 轨迹效果优化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

目前作为我游戏中的轨迹效果,我每 5 帧都会将精灵的半透明纹理副本添加到轨迹列表 <> 中.

Currently as a trail effect in my game I have for every 5 frames a translucent texture copy of a sprite is added to a List<> of trails.

这些轨迹的 alpha 值每帧递减,绘制函数遍历列表并绘制每个纹理.一旦它们达到 0 alpha,它们就会从列表中删除<>.

The alpha values of these trails is decremented every frame and a draw function iterates through the list and draws each texture. Once they hit 0 alpha they are removed from the List<>.

结果是在移动实体后面有一个不错的小轨迹效果.问题是对于大约 100 多个实体,帧速率开始急剧下降.

The result is a nice little trail effect behind moving entities. The problem is for about 100+ entities, the frame rate begins to drop drastically.

所有轨迹纹理都来自同一个精灵表,所以我不认为这是批处理问题.我分析了代码,在 FPS 下降峰值期间 CPU 强度较低,然后它处于正常 FPS,所以我认为这意味着它的 GPU 限制?

All trail textures come from the same sprite sheet so i dont think it's batching issue. I profiled the code and the CPU intensity is lower during the FPS drop spikes then it is at normal FPS so I assume that means its a GPU limitation?

有没有什么办法可以更有效地达到这个效果?

Is there any way to achieve this effect more efficiently?

这是我使用的通用代码:

Heres the general code im using:

// fade alpha
m_alpha -= (int)(gameTime.ElapsedGameTime.TotalMilliseconds / 10.0f);

// draw
if (m_alpha > 0) {
    // p is used to alter RGB of the trails color (m_tint) depending on alpha value
    float p = (float)m_alpha/255.0f;
    Color blend = new Color((int)(m_tint.R*p), (int)(m_tint.G*p), (int)(m_tint.B*p), m_alpha);               
    // draw texture to sprite batch
    Globals.spriteBatch.Draw(m_texture, getOrigin(), m_rectangle, blend, getAngle(), new Vector2(m_rectangle.Width/2, m_rectangle.Height/2), m_scale, SpriteEffects.None, 0.0f);                
} else {
        // flag to remove from List<>
        m_isDone = true;               
}

我想我应该注意,给予路径类的 m_texture 是对所有路径共享的全局纹理的引用.我注意到为每个路径创建一个硬拷贝.

I guess i should note, the m_texture given to the trail class is a reference to a global texture shared by all trails. Im note creating a hard copy for each trail.

如果我简单地注释掉 SpriteBatch.Draw 调用,即使我为数百个对象的每一帧分配了一条新的轨迹,帧数也不会下降......必须有更好的方法来做到这一点.

If I simply comment out the SpriteBatch.Draw call, even when im allocating a new trail every single frame for hundreds of objects there is no drop in frames... there has got to be a better way to do this.

推荐答案

通常用于轨迹,而不是在每一帧上清除屏幕,您只需在绘制当前帧之前绘制一个透明的屏幕大小的矩形.因此,前一帧变暗"或颜色模糊",而新帧完全清晰"和明亮".重复此操作时,会从所有先前的帧中生成一条轨迹,这些帧永远不会被清除而是变暗".

Usually for trails, instead of clearing the screen on every frame, you simply draw a transparent screen-sized rectangle before drawing the current frame. Thus the previous frame is "dimmed" or "color blurred" while the newer frame is fully "clear" and "bright". As this is repeated, a trail is generated from all the previous frames, which are never cleared but rather "dimmed".

这种技术非常有效,它用于著名的 Flurry 屏幕保护程序 (www.youtube.com/watch?v=pKPEivA8x4g).

This technique is VERY efficient and it is used in the famous Flurry screensaver (www.youtube.com/watch?v=pKPEivA8x4g).

为了使轨迹更长,您只需增加用于清除屏幕的矩形的透明度.否则,您会使其更不透明,从而使路径更短.但是请注意,如果通过使矩形太透明而使轨迹太长,则可能会留下一些由于 alpha 混合而导致的轨迹的轻微痕迹,即使经过很长时间也可能不会完全擦除.Flurry 屏幕保护程序受到这种伪影的影响,但有一些方法可以弥补它.

In order to make the trails longer, you simply increase the transparency of the rectangle that you use to clear the screen. Otherwise, you make it more opaque to make the trail shorter. Note, however, that if you make the trails too long by making the rectangle too transparent, you risk leaving some light traces of the trail that due to alpha blending, might not completely erase even after a long time. The Flurry screensaver suffers from this kind of artifact, but there are ways to compensate for it.

根据您的情况,您可能需要调整该技术.例如,您可能希望有多个绘图层,允许某些对象留下轨迹,而其他对象不生成轨迹.

Depending on your situation, you might have to adapt the technique. For instance, you might want to have several drawing layers that allow certain objects to leave a trail while others don't generate trails.

这种技术对于长路径来说比尝试像当前方法那样重绘精灵数千次更有效.

This technique is more efficient for long trails than trying to redraw a sprite thousands of times as your current approach.

另一方面,我认为您的代码中的瓶颈是以下几行:

On the other hand, I think the bottleneck in your code is the following line:

Globals.spriteBatch.Draw(m_texture, getOrigin(), m_rectangle, blend, getAngle(), new Vector2(m_rectangle.Width/2, m_rectangle.Height/2), m_scale, SpriteEffects.None, 0.0f);   

像 Draw() 这样的数千个 GPU 调用是低效的.如果缓冲区中有一个多边形列表,其中每个多边形都位于正确的位置并且存储了透明度信息,那么效率会更高.然后,通过对 Draw() 的 SINGLE 调用,您可以渲染具有正确纹理和透明度的所有多边形.抱歉,我无法为您提供代码,但如果您想继续采用您的方法,这可能是您前进的方向.简而言之,你的GPU当然可以一次绘制数百万个多边形,但它不能多次调用Draw()...

It is inefficient to have thousands of GPU calls like Draw(). It would be more efficient if you had a list of polygons in a buffer, where each polygon is located in the correct position and it has transparency information stored with it. Then, with a SINGLE call to Draw(), you can then render all polygons with the correct texture and transparency. Sorry I cannot provide you with code for this, but if you want to continue with your approach, this might be the direction you are headed. In short, your GPU can certainly draw millions of polygons at a time, but it can't call Draw() that many times...

这篇关于C# XNA 2D 轨迹效果优化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆