Note that there are some explanatory texts on larger screens.

plurals
  1. POXNA/Monogame, Fastest way to draw multiple sheared/skewed sprites
    text
    copied!<p>I normally work with <code>SpriteBatch</code> in XNA/Monogame for 2d games and have just recently delved into 3D drawing methods such as <code>DrawUserIndexedPrimatives</code> and the like. I'm working on a project where our animators would like to have the ability to shear sprites and textures.</p> <p>With <code>SpriteBatch</code> you can pass in a matrix on <code>SpriteBatch</code> begin to shear an object. Something like:</p> <pre><code>//translate object to origin Matrix translate1 = Matrix.CreateTranslation(-rectangle.X, -rectangle.Y, 0); //skew the sprite 33 degrees on the X and Y axis Matrix skew = Matrix.Identity; skew.M12 = (float)Math.Tan(33 * 0.0174532925f); skew.M21 = (float)Math.Tan(33 * 0.0174532925f); //translate object back Matrix translate2 = Matrix.CreateTranslation(rectangle.X, rectangle.Y, 0); Matrix transform = translate1 * skew * translate2; _spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.NonPremultiplied, SamplerState.PointWrap, DepthStencilState.Default, RasterizerState.CullCounterClockwise, null, transform); _spriteBatch.Draw(_texture, rectangle, Color.White); _spriteBatch.End(); </code></pre> <p>The obvious down side of the this is that it requires you make a new <code>SpriteBatch</code> begin and end call for every sheared sprite. We currently only need 2 calls to <code>SpriteBatch</code> begin in our game. One for UI and one for World stuff. Our artist would want to use shear for stuff like swaying trees or animating legs and limbs on creatures so I could see that number jumping to 10+ separate batches if we gave them the option. </p> <p>An average level has around 250 elements each containing 10-20 sprites.</p> <p>I've written a test for Android that calls draw on 1000 sprites. Without any skewing it can draw all 1000, 600 times in about 11 seconds or approximately 53fps. But if I skew every tenth sprite (adding 100 new <code>SpriteBatch</code> call) it takes 47 seconds, or approximately 12fps.</p> <p>That's really bad. Even for just 200 sprites (every tenth one skewed) the test drops to 28fps.</p> <p>So I've also created the same test using Quads drawn with <code>DrawUserIndexedPrimitives</code>. Each Quad uses a shared <code>BasicEffect</code> created in the Game class and passed in via the <code>Sprite</code> classes constructor. I set the World Matrix and Texture before each <code>pass.Apply()</code> like so:</p> <pre><code>if (_basicEffect != null) { foreach (EffectPass pass in _basicEffect.CurrentTechnique.Passes) { _basicEffect.World = Transform; _basicEffect.Texture = _texture; pass.Apply(); GraphicsDevice.DrawUserIndexedPrimitives &lt;VertexPositionNormalTexture&gt;( PrimitiveType.TriangleList, _quad.Vertices, 0, 4, _quad.Indices, 0, 2); } </code></pre> <p>For 1000 sprites, no skew, this gives me 12fps (I imagine it's like making 1000 <code>spriteBatch</code> calls). That's really bad. But for only 200 sprites with every 10th sprite skewed, I get 46fps which is significantly better than <code>SpriteBatch</code> (Even though I'm calling <code>DrawUserIndexedPrimitives</code> like 200 times).</p> <p>---MY QUESTION---</p> <p>How could I batch my calls to <code>DrawUserIndexedPrimitives</code> (or something similar) while keeping my sprites each contained in their own class that inherits <code>DrawableGameComponent</code>? That last parts pretty important just due to the nature of our game engine and the way it handles animation and collision and stuff.</p> <p>I've read what I can about Vertex Buffers and <code>DrawIndexedPrimitives</code>, but don't quite have my head wrapped around it, and don't know how I'd assign new textures and world transforms to sprites drawn in this way.</p> <p>Should I expect similar/better performance than <code>SpriteBatch</code> if I batch these calls?</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload