2D Toolkit Forum

2D Toolkit => Support => Topic started by: aikitect on June 28, 2014, 02:37:59 am

Title: [Creating a Customizable 2D Character] Creating Atlases Dynamically at Runtime
Post by: aikitect on June 28, 2014, 02:37:59 am
Hello, I am trying to create a customizable 2D character that is comprised of 30 different sprites.  Assuming that there are 10 variations of each sprite, there would be 300 sprites in total.  I also want to have multiple characters on screen at one time.  As a result, I am trying to figure out what's the best way to render a given character at runtime if I know the sprite names that need to be shown.  There are three solutions:


I want to attempt the last solution.  However, I am trying to figure out how to do that with TK2D.  I have been reading other threads such as this one: http://2dtoolkit.com/forum/index.php/topic,2576.15.html.

However, I have a few questions about the workflow for this works.  From what I gather, it work as follows.


Can you help advise on the workflow above or suggest something else completely if it is not correct.
Title: Re: [Creating a Customizable 2D Character] Creating Atlases Dynamically at Runtime
Post by: unikronsoftware on June 28, 2014, 12:54:19 pm
#3 is not necessary if you do #1 and #2. Once you get to that point, you'll be able to use the sprites directly.
The render texture solution is much more optimal alternative to PackTextures, which is really really slow.
Title: Re: [Creating a Customizable 2D Character] Creating Atlases Dynamically at Runtime
Post by: aikitect on June 28, 2014, 05:30:03 pm
Can you explain the basic workflow of using render textures?  I watched a few tutorials and wasn't really able to piece it together.  Are you supposed to use RenderTexture to generate the atlas and then plug it into tk2dSpriteCollectionData.CreateFromTexture?  Is there sample code available for this?
Title: Re: [Creating a Customizable 2D Character] Creating Atlases Dynamically at Runtime
Post by: unikronsoftware on June 28, 2014, 09:12:18 pm
Yes, you use render textures to generate the atlas - this is a lot faster than writing into texture2D, and call CreateFromTexture using the render texture. I am not aware of any sample code for this.

At the end of the day though, if you need something and its not performance critical, the pack textures method will work fine.
Title: Re: [Creating a Customizable 2D Character] Creating Atlases Dynamically at Runtime
Post by: aikitect on June 29, 2014, 09:38:39 pm
Ok, so if there's no sample code, can you give guidance on the following rough algorithm?

1) Create a RenderTexture called characterTexture.
2) Create a camera in the scene. (Should this camera be a tk2dCamera?)
3) Pack the relevant 2D sprites into the field of view of the camera.  Save the sprite names in names, save the width and height of each sprite in regions, and save the center (since they are center-anchored) of each sprite in anchors.
4) Call tk2dSpriteCollectionData.CreateFromTexture.

Code: [Select]
tk2dSpriteCollectionData.CreateFromTexture(
    characterTexture,
    tk2dSpriteCollectionSize.ForTk2dCamera(Camera.main),
    names,
    regions,
    anchors
);

Two more questions related to this.  Is there a packing algorithm that you suggest using (perhaps the one that tk2d uses)?  Also, how fast is tk2dSpriteCollectionData.CreateFromTexture?  Can it be done in realtime (e.g. if I swap out a red leg piece for a blue leg piece, can I refresh the atlas by calling CreateFromTexture quickly)?
Title: Re: [Creating a Customizable 2D Character] Creating Atlases Dynamically at Runtime
Post by: unikronsoftware on June 30, 2014, 12:09:48 pm
The camera doesn't need to be a tk2d camera, you will just need to arrange everything into this atlas, so whatever way you wanna do it is fine. Be sure to only draw this once and not repeatedly

tk2dSpriteCollectionData.CreateFromTexture can be updated at runtime, performance should be fine. You can also do this incrementally - look into the source code to this function to see how you can do modify things on the fly.

One thing to note - if your modify the atlas in such a  way that existign sprites will no longer be valid, you will need to find them and call ForceBuild to have them regenerate the geometry.
Title: Re: [Creating a Customizable 2D Character] Creating Atlases Dynamically at Runtime
Post by: aikitect on June 30, 2014, 06:22:43 pm
Be sure to only draw this once and not repeatedly.  How do I ensure that I only draw the texture once?

One thing to note - if your modify the atlas in such a  way that existign sprites will no longer be valid, you will need to find them and call ForceBuild to have them regenerate the geometry.  What would I be calling ForceBuild on?
Title: Re: [Creating a Customizable 2D Character] Creating Atlases Dynamically at Runtime
Post by: unikronsoftware on July 01, 2014, 10:20:33 am
Be sure to only draw this once and not repeatedly.  How do I ensure that I only draw the texture once?
You will need to either call camera.Render manually or turn off the camera after a frame. You should read up about how all of this stuff works - this approach requires a fair bit of understanding about how unity works. Answers.unity3d.com will help. If you don't want to invest the time to understand all this use Texture2D.PackTextures.

One thing to note - if your modify the atlas in such a  way that existign sprites will no longer be valid, you will need to find them and call ForceBuild to have them regenerate the geometry.  What would I be calling ForceBuild on?
On the tk2dSprite class for all the existing sprites.
Title: Re: [Creating a Customizable 2D Character] Creating Atlases Dynamically at Runtime
Post by: aikitect on July 02, 2014, 06:43:48 am
Thanks, what exactly makes Texture2D.PackTextures slow in the first place?
Title: Re: [Creating a Customizable 2D Character] Creating Atlases Dynamically at Runtime
Post by: unikronsoftware on July 02, 2014, 11:09:35 pm
Its done in software, and requires copies of source and destination textures in main memory.
Title: Re: [Creating a Customizable 2D Character] Creating Atlases Dynamically at Runtime
Post by: aikitect on July 20, 2014, 06:18:35 am
Hey, so I'm in the middle of implementing RenderTexture-based atlases.  I have the following code that creates a RenderTexture:

Code: [Select]
    private Texture2D CreateAtlasTexture(int textureSize)
    {
    RenderTexture renderTexture = new RenderTexture(textureSize, textureSize, 24);
    Texture2D atlasTexture = new Texture2D(textureSize, textureSize, TextureFormat.ARGB32, false);
   
    RenderCamera.aspect = 1.0f;
    RenderCamera.targetTexture = renderTexture;
    RenderCamera.Render();
   
    RenderTexture.active = renderTexture;
                atlasTexture.ReadPixels(new Rect(0.0f, 0.0f, textureSize, textureSize), 0, 0);
                atlasTexture.Apply();
    RenderTexture.active = null;
    RenderCamera.targetTexture = null;
   
    return atlasTexture;
     }

However, when I run this code, and the camera preview looks like the screenshot below, I get a Texture2D that is distorted.  Can you help identify why this might be happening?  I feel like it is a camera setting (it seems like it is being previewed at 1024x768 and shrunk to 512x512), but I'm not sure how to fix this.  Thanks!

Title: Re: [Creating a Customizable 2D Character] Creating Atlases Dynamically at Runtime
Post by: unikronsoftware on July 20, 2014, 11:27:03 am
Dont use a tk2dcamera for this. The tk2d camera is meant for screen cameras, its performing screen aspect ratio correction on this which you dont want.
Title: Re: [Creating a Customizable 2D Character] Creating Atlases Dynamically at Runtime
Post by: aikitect on July 20, 2014, 05:25:37 pm
Great, I got the RenderTexture working.  Thank you so much!  Now the last part is trying to get the right regions and anchors for each of the sprites.  So using my packing algorithm, I get back a list of Rects that contain the bounds of each sprite.  For example, I will get back one Rect myRect that is:

x: 466.0
y: 84.0
width: 42.0
height: 34.0

(This is using the bottom left as the origin.)

I am trying to translate this into the the region and anchor (preferably centered) that is given to tk2dSpriteCollectionData.CreateFromTexture.  I have tried sending the following but they don't work:

Code: [Select]
region = myRect;
anchor = myRect.center;

region = myRect.NormalizeBy(100.0f); // This divides each dimension of the Rect by 100.0f.
anchor = myRect.center / 100.0f;

Also, my CreateFromTexture call is as follows:

Code: [Select]
spriteCollection = tk2dSpriteCollectionData.CreateFromTexture(atlasTexture,
tk2dSpriteCollectionSize.PixelsPerMeter(100.0f), allSprites, spriteRegions, spriteAnchors);
Title: Re: [Creating a Customizable 2D Character] Creating Atlases Dynamically at Runtime
Post by: unikronsoftware on July 21, 2014, 12:59:30 pm
What do you mean by it dont work?
Title: Re: [Creating a Customizable 2D Character] Creating Atlases Dynamically at Runtime
Post by: aikitect on July 21, 2014, 04:31:58 pm
I have a Spine SkeletonAnimation that uses this new SpriteCollection to generate a character using the sprites in the SpriteCollection.  When I use a pre-built SpriteCollection that I created via the Editor, the character shows up on the screen.  However, when I create the SpriteCollection via CreateFromTexture, nothing shows up at all on the screen.
Title: Re: [Creating a Customizable 2D Character] Creating Atlases Dynamically at Runtime
Post by: unikronsoftware on July 21, 2014, 06:32:10 pm
I can't really comment about the spine integration as I didn't write it.
Try creating a sprite with it.
x and y is from the top left, corresponding to an image in Photoshop / TexturePacker / etc - you're probably just drawing a transparent part of the texture - creating a sprite with it will let you work that out quickly, you'll should at least see transparent geometry when the sprite is selected.
Title: Re: [Creating a Customizable 2D Character] Creating Atlases Dynamically at Runtime
Post by: aikitect on July 22, 2014, 02:57:20 am
Great, I got it to work.  Now I'm running into one (hopefully) last issue.  When I actually output the character onto the screen, I get the attached image.  If you look closely, you will see a white outline around each body part of the character (the arms are a good example).  In addition, there are white pixels that appear above the left ear and to the right of the right ear that are not part of the source image.

Why is this happening?  I did some reading on it, and my hypothesis is that it is related to the shader that is used to create the RenderTexture.  Do you have any idea how I can fix this?
Title: Re: [Creating a Customizable 2D Character] Creating Atlases Dynamically at Runtime
Post by: aikitect on July 22, 2014, 04:31:00 am
Nevermind figured it out.  I searched up another thread and found that I needed to turn on premultiplied alpha and set the shader to PreMulVertexColor.  Also, the weird pixels I saw were because I didn't include padding into my algorithm for generating the atlas texture.  Once I did that, everything worked.  Thank you so much for your help, this is amazing! :)