C#XNA 2D追踪效果优化 [英] C# XNA 2D trail effect optimization

查看:109
本文介绍了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.

所有步道纹理都来自相同的Sprite表,所以我不认为这是批处理问题.我分析了代码,在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;               
}

我想我应该注意,给Trail类提供的m_texture是对所有Trail共享的全局纹理的引用.我要注意为每条足迹创建一份纸质副本.

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()的单次调用,即可使用正确的纹理和透明度渲染所有多边形.抱歉,我无法为您提供代码,但是,如果您想继续使用您的方法,这可能就是您的前进方向.简而言之,您的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天全站免登陆