Optimizing the C # XNA 2D path effect

As a side effect in my game, for every 5 frames, a translucent texture copy of the sprite is added to the <> trail list.

The alpha values ​​of these tracks are decremented every frame, and the draw function iterates through the list and draws each texture. Once they hit 0 alpha, they will be removed from the <> list.

The result is a nice small trail effect for moving objects. The problem is with more than 100 objects, the frame rate starts to drop dramatically.

All footprint textures come from the same sprite sheet, so I don't think this is a package issue. I have profiled the code and the CPU intensity is lower during bursts of FPS drops, then it is at normal FPS, so I guess it means that this is a GPU limitation?

Is there a way to achieve this effect more efficiently?

Here's the generic 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;               
}

      

I think I should note that the m_texture assigned to the trail class is a reference to the global texture shared by all trails. Im noticing creating a hard copy for each trail.

EDIT: If I just comment out the call to SpriteBatch.Draw, even when I allocate a new trail for each frame for hundreds of objects, there are no drops in the frames ... there must be a better way to do it.

+3


source to share


1 answer


Typically for trails, instead of clearing the screen on every frame, you simply draw a screen-sized transparent rectangle before drawing the current frame. Thus, the previous frame is “darkened” or “washed out”, while the new frame is completely “crisp” and “bright”. As this repeats, the trail is generated from all previous frames, which are never cleared, but rather "dimmed".

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

To make the tracks longer, you simply increase the transparency of the rectangle that is used to clear the screen. Otherwise, you will make it more opaque to make the trail shorter. Note, however, that if you make tracks for too long, making the rectangle too transparent, you run the risk of leaving some trail marks that, due to alpha blending, may not completely erase even after a long time. The Flurry screensaver suffers from this kind of artifacts, but there are ways to compensate for this.

Depending on your situation, you may have to adapt the technique. For example, you may want to have multiple drawing layers that allow some objects to leave traces while others do not generate alignments.



This method is more efficient for long traces than trying to redraw the 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);   

      

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

+3


source







All Articles