How to get texture region of atlas?

:information_source: Attention Topic was automatically imported from the old Question2Answer platform.
:bust_in_silhouette: Asked By Caterpiggle

When using an atlas texture for sprite nodes, I’ve noticed that the texture of the node is not the region you selected, but rather the entire atlas texture. The engine selects the region when instancing, but the node itself has the entire atlas as its texture property.

When trying to display the node’s texture in something like an itemlist, it displays the entire atlas texture, since that IS the node’s texture. Is there any way to grab only the region of the atlas that the node is using as its texture without redrawing the region?

I’m a bit confused as to what you mean. An AtlasTexture is basically a sub-region of an existing texture, it does not create a copy or anything. Of course the AtlasTexture itself is referencing the entire atlas, but that’s just how they work, they are sub-regions, not copies (which would be wasteful). When I create one and assign it to a Sprite, I see that sub-region is drawn, and I also see the same sub-region in the inspector :expressionless:
Same with ItemList, when adding icons from an AtlasTexture, it correctly draws the region.

However, if you try using an AtlasTexture somewhere, but see the entire atlas being drawn, it could be a bug.

Zylann | 2019-03-24 20:29

This is how I would expect it to work. I assign an atlas to the sprite’s texture, define a region, and everything works correctly in terms of instancing that object.

Looking at the inspector, both the “texture” and “atlas” regions show the entire atlas, however the 2D main window shows the correct region as the sprite texture. So when I try to access the sprite’s texture, it gives me the entire atlas instead of the region I defined, even though it works correctly everywhere else.

Here is what I’m talking about. You can see the texture and atlas in the inspector on the right as the entire atlas, but the region is working correctly in the window.

https://imgur.com/t8yIVNB

Caterpiggle | 2019-03-24 20:50

I assign an atlas to the sprite’s texture, define a region, and everything works correctly in terms of instancing that object.

If by “atlas” you mean a texture, that should already be working well.

Looking at the inspector, both the “texture” and “atlas” regions show the entire atlas, however the 2D main window shows the correct region as the sprite texture.

So instead of using an AtlasTexture, you used the region property of Sprite?
In that case, of course the texture property is going to return you the entire texture… because the region was defined in the sprite itself, not the texture, and is only used when this particular sprite is drawn. Instancing it should work, though.

If you want to define a sub-region of an atlas and be able to re-use it wherever you like without having to redefine it and see only the region in the inspector, you should create an AtlasTexture resource.

If this isn’t enough, I’d like to see screenshots of the problem and what you are trying to achieve.

Zylann | 2019-03-24 21:08

I suppose what I’m really asking is what region to use in the inspector. I posted a picture in the above comment so you can see what I’m referring to.

If I define a region under the atlas section in the sprite inspector, every node that uses the atlas will use that region. The documentation is not clear to me about what these separate regions are referring to.

Here is a picture of the above scenario:
https://imgur.com/z5FJnC4

To me, this looks correct. The texture shows just the region, and it would seem that this would work correctly. However, now all other nodes that reference this atlas have the same texture!

Caterpiggle | 2019-03-24 21:17

The way Godot shows this is confusing too: it’s supposed to be a sub-resource but in the inspector it almost looks like an extra property which unfolds when you click on the resource, while it’s actually a property of the resource, not the sprite xD

I see you used an AtlasTexture. So yes, when you use AtlasTextures, they are all shared by default, even if you didnt save them as a .tres file. That means if you duplicate the sprite, it will use the same AtlasTexture as the original. To break that link, right-click on the property and choose “Make unique”. This has to be done each time you duplicate the node, though, but that’s the take on using AtlasTextures. They are here to allow a workflow where you can define them once and re-use them.

If you prefer a workflow in which every region defined is always unique per node, don’t use AtlasTexture and use the Region properties of the sprite, although this is more limited. Wether to use that or AtlasTextures is up to which workflow you prefer.

Zylann | 2019-03-24 22:10

Well I guess that worked, never would have figured that out. Is there any way you can see what regions are unique?

Maybe I am misunderstanding, but what would be the point of using an atlas that isn’t unique per node? Does having multiple nodes that use the same texture load the texture more than once?

Caterpiggle | 2019-03-24 22:22

Is there any way you can see what regions are unique?

Unfortunately no, “uniqueness” is not a property of resources. You know it yourself by remembering that when you make your scenes. Convention rules can help. One way to be absolutely sure is to look at the .tscn file itself and see how many times the SubResource( id ) is appearing, where id is an index for that resource.
What I ususally do is to save AtlasTextures as .tres anyways, so I can also edit them without having to open the scene where I used it, and it’s easier to check where it was used by file search.

what would be the point of using an atlas that isn’t unique per node?

Again, you use the word “Atlas” but I assume you mean “AtlasTexture”, which is just a sub-region of a texture packed into a resource. The point of using such resources is being able to re-use them. If you need the same sub-region for something else in your game, you can pick up the same resource that you could have saved as a file beforehands.

Another use could be automatic spritesheet tools, which can slice an existing spritesheet and output a bunch of AtlasTexture files corresponding to each sprite in the sheet, which can then be used wherever needed.

Yet another use is the opposite: you could start with separate textures for everything, and ask a tool to pack them all automatically into atlases, replacing each property by generated AtlasTextures. This was an option in Godot 2.

Does having multiple nodes that use the same texture load the texture more than once?

Godot loads the resource once, but if more nodes need it too, it is cached in memory so subsequent loads cost almost nothing. This is partly why nodes share resources by default as well. If that wasn’t the case, you would end up duplicating textures themselves, which would indeed cause big waste of memory.

Similarly, if you have 10 different AtlasTextures referencing the same texture, each AtlasTexture will be loaded because they all are unique, but because they share the same texture, that one will be loaded only once and not 10 times.

Zylann | 2019-03-24 22:48

Thanks for helping me out.

My clear lack of understanding makes me wary of attempting to continue using an AtlasTexture. Using sprite region properties, however, I can’t see a way around the sprite’s texture property containing the entire spritesheet. There must be a better way to access a region of a texture, regardless of workflow choice.

Caterpiggle | 2019-03-24 23:01

I can’t see a way around the sprite’s texture property containing the entire spritesheet

Well, that’s how things go. By not using an AtlasTexture resource, the Sprite itself gets to contain the sub-rect information directly, nothing wrong with this. And to draw that sub-rect, the sprite needs a reference to the texture. It doesn’t “contain” the entire atlas, it just has a handle on it so it can use part of it. The same goes for AtlasTextures themselves.

Then the inspector shows a thumbnail of the entire atlas on that property because that’s what it does for any kind of object having a texture property, not just Sprite. There isn’t special code saying “Oh, that texture property is on a Sprite, let’s show a sub-region instead”.

Also, when you click the texture property, what you are shown is the texture resource itself, embedded as a “sub-inspector”. If you double-click on the texture in the file explorer, it will show you the same thing. That’s why it shows the entire atlas.
This is a new feature that was added in 3.1, supposedly to make it quicker to modify resources assigned to nodes.

Zylann | 2019-03-24 23:13

Thanks for helping me understand. I’m aware of the region not being its own texture, and that the texture of a sprite should be the entire spritesheet. It simply wouldn’t make sense otherwise.

I suppose I was just being lazy and hoping that I could loop through nodes and retrieve a texture based on their ID, but of course this texture was the referenced texture of each node, not the region.

The best way I can see of achieving what I was trying to do is to hardcode the region_rects of each node’s region and storing them in a singleton. Not very elegant but gets the job done.

Caterpiggle | 2019-03-24 23:28