SpriteObject's and UV's

Oct 15, 2011 at 8:15 PM
Edited Oct 15, 2011 at 9:34 PM

Hi,

Having a few issues with getting my spritesheet to display correctly. So far I can only get it to display the whole spritesheet or nothing at all.

I have a text file which is read into a class that stores the sourceRectangles for each sprite on the spritesheet. What I'm trying to do is use that information, the X, Y, Width and Height, to correctly display the sprite using IGF and a SpriteObject.

I think the SpriteObject.Size and UVSize actually scales the object and material? If so, how can I use a Width and Height value?

Is it possible to use source rectangle information to correctly display a single sprite from a sheet? I've tried many combinations of changing UVSize, Size, UVPosition and it either renders nothing or the entire spritesheet.

The SunBurn Top-Down example does the following:
Size = Vector2.One * 0.5f;
UVSize = new Vector2(0.25f);
UVPosition = new Vector2(X, Y) * 0.25f where X and Y is the co-ordinates of the sprite

Mine:
Size = Vector2.One;
UVSize = Vector2.One;
UVPosition = new Vector2(X, Y) where X and Y is the co-ordinates of the sprite

Mine renders nothing with those settings, but I can't see where I'm going wrong. If I set the Size to the Width and Height of my source rectangle, it renders extremely large, but still renders the whole spritesheet. My material is set to Wrap, but it is wrap in the sunburn example too, so I'm not sure if that is what the problem is. Out of all my combinations and attempts, I've never managed to render a single portion of the spritesheet, so i think I'm missing something obvious here.

Any help/explanations greatly appreciated.

Love IGF so far!

Coordinator
Oct 15, 2011 at 11:11 PM

Hi,

First, since SpriteObjects extend SceneObject, they can be added to the ObjectManager and thus, you can see their BoundingBox if using the SunBurn DebugRenderManager. I highly advice you to use it to see if the BoundingBox of your SpriteObject instances are placed where you expect them to be at the size you expect them ;)

Second, I never really dig into SpriteSheet support and animation so I can't really tell you if I'm doing something wrong: basically, I used SunBurn principles to create the meshes in the SpriteContainer using the Add() method. You can see the code:

public void BeginFrameRendering(ISceneState scenestate)
        {
            foreach (SpriteContainer container in _containers.Keys)
            {
                if (container.RenderableMeshes.Count == _containers[container].Count &&
                    container.UpdateType == UpdateType.None)
                    continue;

                container.Begin();

                foreach (SpriteObject sprite in _containers[container])
                {
                    if (sprite.UpdateType == UpdateType.Automatic)
                    {
                        if (sprite.Material == null) continue;

                        container.Add(sprite.Material, sprite.Size, sprite.Position, sprite.Rotation, sprite.Origin,
                                      sprite.UVSize, sprite.UVPosition, sprite.LayerDepth);
                    }
                }

                container.End();
            }

 So, normally, if you can get the same principles as the Top down SunBurn sample in your game, I don't see why it doesn't render.

I opened a few days ago a new ticket to ensure full and easy support for SpriteSheet and Animation. http://igf.codeplex.com/workitem/318



Regards

Oct 15, 2011 at 11:51 PM
Thanks for the reply.

I couldn't really see why it wouldn't work, but I do think its more a problem with my code than the framework. Just wasn't sure if I was missing something obvious.

If i figure it out ill post back anyway, cheers
Oct 18, 2011 at 9:15 AM
Edited Oct 18, 2011 at 7:16 PM

Hey, just quick post to say that there isn't anything wrong with the code, it was my code that was incorrect.

The sunburn example scales the UVSize by 0.25f, and I didn't realise at the time that their spritesheet has 4 * 4 sprites on it, once I realised that it all seemed much clearer (even though I'd already spent a long time staring at the spritesheets!).

So all I needed to do is convert my width and height of source rectangles, into a scale value between 1 and 0.

Editing this post to correct a few mistakes

UVSize = Size of the Sprite on the spritesheet, expressed as a float between 0f and 1f. 
UVPosition = Position of the sprite, expressed as a float between 0f and 1f.
Size = Size of the SpriteObject. Or, the Scale of the sprite if you think of it in terms of how you'd use SpriteBatch
Piece of cake! =)
Coordinator
Oct 18, 2011 at 9:28 AM

Great to see that you come through this :)

Is there anything convenient you'd like to see added to the SpriteObject class to ease your day adding SpriteSheet & Animated Sprites support by just plugging in the SpriteSheet?

Anything redundant you noticed would be repeated for each sprite you'll create there?

Thanks

Oct 18, 2011 at 10:50 AM

Hi again,

Creating the spriteObject was pretty straight-forward, so no suggestions there.

Only thing I noticed was that using Size(1f, 1f) caused the spritesheet to be flipped horizontally and vertically when using the IGF Target2D camera. There was a post about this on the sunburn forums (I don't have the link at the moment) but I think it was because of the co-ordinate system used that was required for the deferred rendering and not an IGF issue.

         +Y
+X  ---+--- -X
          -Y

Easily solved by using Size (-1f, -1f), but not sure how this affects the positions of the sprites just yet, whether they use the top-left corner as the default origin like SpriteBatch, or the centre of the sprite like a SceneObject (which I'm assuming it is). Once I've built a simple test level I'll be able to see more clearly how this works, as it could just be my code causing this.

As my level editor was based around the SpriteBatch co-ordinate system, I'll have to re-jiggle a few things to make it match the SunBurn one when importing a level, but apart from the flipping sprites, can't really say there was anything that caused problems or was unexpected.

Everything was pretty straight forward. Create a new material for each spritesheet, create and start a new spritecontainer, load the level text file, loop through all the level pieces and create a new spriteobject for each one, give it the appropriate spritesheet material, add them to the spritecontainer, close the container and submit that to the scene interface, hit F5 and done. These are all just static sprites, but once I look at getting my character editor hooked into sunburn, it will be a bit more complex, but we'll see how that goes, it's a fun little project on the side.

Not sure if there's anything here you'll find helpful, I'm still very messy when it comes to organising code =)

 

Jan 24, 2012 at 8:11 AM

Do you guys know how to get the physical pixel width of a SpriteObject? The problem I am having in my code is that I wrote a pipeline for importing a sprite map of pixel coordinates and pixel sizes relative to the input image where each frame exists however the size of the Sprite Object is 0f -> 1f and doesn't appear to expose a pixel size. Without this information I cannot convert the pixel sizes in the sprite sheet to the appropriate 0->1 scale. I hope this makes some kind of sense :)

Summary of what I am trying to do...

1) Create a custom pipeline that imports a .txt file that contains pixel coordinates and sizes for each frame in the image (Success)

2) Create a custom pipeline that processes the .txt file in to an array of rectangles associated with friendly names for each frame (Success)

2) Create a custom SpriteSheet object that derives from SpriteObject (Success)

3) Have a property on my SpriteSheet object that when set to the frame name it will automatically adjust the UVSize and UVPosition of the underlying SpriteObject based on the rectangle it pulls from the array (key/value pairs) (Success)

4) Compute the new UVSize and UVPosition properly based on the physical pixel size and location reported from the pipeline (FAIL!!!).

The big problem here is that I cannot for the life of me get the physical pixel height and width from the SpriteObject itself. If I could obtain this data I would be able to simply divide 1F / SpriteObject.Size * SpriteFrame.X, etc to get the percentage based values the system likes. I could override the SpriteObject load content and obtain the width/height there and expose them however that feels super hacky and I would rather do it the correct way if there is one.

Coordinator
Jan 24, 2012 at 10:51 AM

Hi Barnacules,

IGF's SpriteObject is a wrapper object for what is normally submitted to SunBurn's SpriteContainer which inherits from SceneObject so that it can react to SunBurn's builtin collision system.

As a consequence, it uses a "Material" at its core to define the sprite texture. This Material can be any Effect base class including SunBurn's forward or deferred Materials.

If you want to get the physical pixel size of a texture, you'll have to cast the SpriteObject.Material property to the underlying type it really uses and then go through this Effect type properties to get the texture you're interested to use.

For instance, if you are using SunBurn's forward material, you'd use something like:

var mySpriteObjectMaterial = (LightingEffect)mySpriteObject.Material;

int textureWidth = mySpriteObjectMaterial.DiffuseMapTexture.Width;
int textureHeight = mySpriteObjectMaterial.DiffuseMapTexture.Height;

For a deferred material, you'd use DeferredObjectEffect instead.
Both classes inherit from BaseMaterialEffect so you could also use it to cast the SpriteObject.Material.

Just make sure to access it after it is actually created using the SpriteManager.CreateSpriteObejct() method as otherwise the Material property would be set to null.