-
-
Notifications
You must be signed in to change notification settings - Fork 58
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Texture Atlases #221
base: main
Are you sure you want to change the base?
Texture Atlases #221
Changes from all commits
900b87f
812630f
f2b046e
4fe9d9b
86800d1
5b2ac96
f2ff876
46528b2
7cdd90e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,276 @@ | ||
# Texture Atlases | ||
|
||
Many textures in Minecraft are compiled within Atlases (also known as sprite sheets) for optimisation purposes. Most of them are automaticaly generated by Minecraft when registered throught the use of datapacks or [Registries][reg] (such as block textures). | ||
|
||
Optionaly, datapacks can register their own [texture atlas sources][txtatlassource], giving more control over wich sprite or image gets included within an atlas. | ||
|
||
Minecraft includes 14 different atlases for different purposes: | ||
|
||
|Altas name |Description| | ||
|-----------------|-| | ||
|`blocks` |Block textures| | ||
|`banner_patterns`|Banner patterns| | ||
|`beds` |Every bed variant (i.e. colors)| | ||
|`chest` |Chest textures| | ||
|`shield_patterns`|Shield textures and patterns| | ||
|`shulker_boxes` |Every shulker related textures (Shulker box variants, head and projectile)| | ||
|`signs` |Sign textures| | ||
|`particles` |Particle textures| | ||
|`paintings` |Every painting| | ||
|`mob_effects` |Potion effect icons| | ||
|`gui` |Every GUI wigets (buttons, scroll bars...)| | ||
|`map_decorations`|Icons displayed on a map (banners, locations...)| | ||
|`armor_trims` |Armor trim patterns for every material| | ||
|`decorated_pot` |Texture for the decorated pot and every sherd| | ||
Comment on lines
+9
to
+24
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Once again, how are the atlases stored in code? How do I use them? |
||
|
||
## Texture Atlas Sources | ||
|
||
Texture atlas sources are JSON configuration files in ressource packs, that control wich textures of a resource pack are included in the atlases. | ||
|
||
Texture atlas sources are located within the `altases` asset folder, under the namespace of the datapack it is gathering textures from. For a datapack named `example_mod` the directory will be located in `resources/assets/example_mod/atlases`. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
||
### Creating a texture atlas source | ||
|
||
To add textures of a datapack to an atlas, a JSON file with the name of the atlas needs to be declared within the `atlases` asset folder. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does this refer to creating a new sprite source list, or adding to an existing sprite source list. I can tell in the codebase it works similar to tags, but it should be explicitly stated. |
||
For example, here is a texture atlas source adding textures to the `blocks` atlas for the `example_mod` datapack: `resources/assets/example_mod/atlases/blocks.json`. | ||
|
||
The file will then be able to declare [sprite sources][spritesource] inside of an array named `sources`. | ||
```json5 | ||
// Inside blocks.json | ||
{ | ||
"sources": [ | ||
// This texture altas source does not | ||
// declare any sprite sources. | ||
Comment on lines
+42
to
+43
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Then what's the point of this example? Just say 'Add sources here'. |
||
] | ||
} | ||
``` | ||
|
||
### Sprite sources | ||
|
||
Minecraft, by default, includes 4 types of sprite sources: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What about NeoForge? They add Also, you write four when there are five listed below. |
||
|
||
|Sprite source type |Description| | ||
|-----------------------|---| | ||
|`directory` |Lists all files in a directory and its subdirectories| | ||
|`single` |Adds a single file| | ||
|`filter` |Removes sprites matching the given pattern| | ||
|`unstitch` |Copies rectangular regions of a file (sprite sheet)| | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This doesn't just imply a sprite sheet, it means any image. |
||
|`paletted_permutations`|Dynamically generate textures in-memory with color sets| | ||
|
||
### Directory source | ||
|
||
A `directory` sprite source adds all files of a directory into the targeted atlas, using the name of a file and a prefix to create a [`ResourceLocation`][resourceloc]. | ||
|
||
|Field |Content| | ||
|--------|--| | ||
|`type` |Should be `minecraft:directory`| | ||
|`prefix`|A prefix that prepends itself to every file's `ResourceLocation` path| | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is not well explained. It means that when storing the loaded resources, its identifier will be appended with provided prefix on its path. It does not affect the source loading itself, only the identifier to reference. For example, a given block texture located at |
||
|`source`|The path to the targeted directory (relative to the `assets/<namespace>/textures` directory)| | ||
|
||
As an example, the folowing file will add all textures within `assets/exmaple_mod/textures/blocks` to the `blocks` atlas: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It will add much more than that. It applies to any namespace. |
||
```json5 | ||
// Inside assets/example_mod/atlases/blocks.json | ||
{ | ||
"sources": [ | ||
{ | ||
"type": "minecraft:directory", | ||
// Prepend all paths with block/ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is wrong for the reasons explained above. |
||
"prefix": "block/", | ||
// Targets the `assets/exmaple_mod/textures/blocks` directory | ||
"source": "blocks" | ||
} | ||
] | ||
} | ||
``` | ||
|
||
### Single file source | ||
|
||
A `single` sprite source adds a single texture to the targeted atlas. | ||
|
||
|Field |Content| | ||
|----------|--| | ||
|`type` |Should be `minecraft:single` | ||
|`resource`|Location of the file (relative to the `assets/<namespace>/textures` directory, implied `.png` and `.png.mcmeta` extension)| | ||
|`sprite` |Optional name for the sprite (defaults to the content of `resource`)| | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Again, this is not well explained. |
||
|
||
As an example, the folowing file will add `assets/exmaple_mod/textures/misc/smiley_face.png` to the `banner_patterns` atlas: | ||
```json5 | ||
// Inside assets/example_mod/atlases/banner_patterns.json | ||
{ | ||
"sources": [ | ||
{ | ||
"type": "minecraft:single", | ||
// Adds `assets/exmaple_mod/textures/misc/smiley_face.png` to banner patterns | ||
"resource": "example_mod:misc/smiley_face", | ||
// replaces the default ResourceLocation | ||
"sprite": "example_mod:banner_patterns/smiley_face" | ||
} | ||
] | ||
} | ||
``` | ||
|
||
### Filtering resources | ||
|
||
A `filter` sprite soure, is not an actual source, it will remove already existing resources from the atlas by matching them with regular expressions. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's still a sprite source, it just remove entries instead of adding them. |
||
|
||
:::info | ||
The order in wich are placed sprite sources matters especialy when using the `filter` source, as it can only remove already existing resources. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's better to just explicitly state that the source filter can only remove registered resources from previously loaded sources, so this should be added after. Also, this admonition should be a warning. |
||
::: | ||
|
||
|Field |Content| | ||
|-----------|--| | ||
|`type` |Should be `minecraft:filter`| | ||
|`namespace`|A regular expression matching the namespace of resources| | ||
|`path` |A reguler experssion matching the path of resources| | ||
Comment on lines
+123
to
+124
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It would be nice to state that it uses regex compiled by |
||
|
||
Taking back the [Directory source][spritesource_directory] example, this time the `filter` will exclude all textures located within the `work_in_progress` directory. | ||
|
||
```json5 | ||
// Inside assets/example_mod/atlases/blocks.json | ||
{ | ||
"sources": [ | ||
{ | ||
"type": "minecraft:directory", | ||
// Prepend all paths with block/ | ||
"prefix": "block/", | ||
// Targets the `assets/exmaple_mod/textures/blocks` directory | ||
"source": "blocks" | ||
}, | ||
// We place the filter after registering block textures | ||
{ | ||
"type": "minecraft:filter", | ||
// Only remove resources inside of the `example_mod` datapack | ||
"namespace": "exmaple_mod", | ||
Comment on lines
+142
to
+143
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This can also match |
||
// Remove resources that starts woth `block/` and contain the word `work_in_progress` | ||
"path":"block/.*work_in_progress.*" | ||
Comment on lines
+144
to
+145
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same issue here. It just needs to contain the string, not only start with it. |
||
} | ||
] | ||
} | ||
``` | ||
|
||
### Unstitching sprite sheets | ||
|
||
An `unstitch` sprite source, takes a single file containing multiple sprites and unstitches them to create multiple resources using rectagular regions to locate them within a texture. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is pedantic, but it does not need to contain multiple sprites. While that is the most common usecase, you can use it in many different ways. |
||
|
||
An `unstitch` sprite source contains the folowing information: | ||
|Field |Content| | ||
|-----------|--| | ||
|`type` |Should be `minecraft:unstitch` | | ||
|`resource` |Location of the file (relative to the `assets/<namespace>/textures` directory, implied `.png` and `.png.mcmeta` extension)| | ||
|`divisor_x`|Used for determining the scale of coordinates on the x axis| | ||
|`divisor_y`|Used for determining the scale of coordinates on the y axis| | ||
Comment on lines
+160
to
+161
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Generally, the divisors should be larger than the texture in question as these are inversely scaling the coordinates. |
||
|`regions` |List of regions to copy from the source image.| | ||
|
||
A `region` is a single sprite within a texture file: | ||
|Field |Content| | ||
|--------|----| | ||
|`sprite`|`ResourceLocation` of the sprite| | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is the identifier of the resource. Saying it's a resource location could mean anything. |
||
|`x` |x coordinate within the file (before scaling by `divisor_x`)| | ||
|`y` |y coordinate within the file (before scaling by `divisor_y`)| | ||
|`width` |width of the sprite (before scaling by `divisor_x`)| | ||
|`height`|height of the sprite (before scaling by `divisor_y`)| | ||
Comment on lines
+168
to
+171
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Scaling will affect the rectangle that is being copied. |
||
|
||
The following file declares 2 sprites contained within the same texture located in `assets/example_mod/textures/gui/sprites.png`: | ||
```json5 | ||
// Inside assets/example_mod/atlases/gui.json | ||
{ | ||
"sources": [ | ||
{ | ||
"type": "minecraft:unstitch", | ||
// Targets the `assets/example_mod/textures/gui/sprites.png` file | ||
"resource": "example_mod:gui/sprites", | ||
// Normal scaling | ||
"divisor_x": 1.0, | ||
"divisor_y": 1.0, | ||
"regions": [ | ||
// Declares the new `example_mod:gui/batery_full` resource | ||
{ | ||
"sprite": "example_mod:gui/batery_full", | ||
"x": 0, | ||
"y": 0, | ||
"width": 8, | ||
"height": 8 | ||
}, | ||
// Declares the new `example_mod:gui/batery_low` resource | ||
{ | ||
"sprite": "example_mod:gui/batery_low", | ||
"x": 8, | ||
"y": 0, | ||
"width": 8, | ||
"height": 8 | ||
} | ||
] | ||
} | ||
] | ||
} | ||
``` | ||
|
||
### Permutating textures | ||
|
||
:::info | ||
//// TODO `paletted_permutations` | ||
::: | ||
|
||
## Datagen | ||
|
||
Like many resources in Minecraft, texture atlas sources can be proceduraly generated using [datagen][dtgn]. | ||
To do so, we extend `SpriteSourceProvider` and override the `gather()` method: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Mention that |
||
|
||
```Java | ||
public class MySpriteSourceProvider extends SpriteSourceProvider { | ||
|
||
// Parameters obtained via GatherDataEvent | ||
public MySpriteSourceProvider ( | ||
PackOutput output, | ||
CompletableFuture<HolderLookup.Provider> lookupProvider | ||
) { | ||
super(output, lookupProvider, "example_mod"); | ||
} | ||
|
||
@Override | ||
protected void gather () | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should match what's in the example JSON. |
||
{ | ||
// Creates a new texture atlas source for the "blocks" atlas | ||
SourceList blocks = atlas( | ||
ResourceLocation.fromNamespaceAndPath("example_mod", "blocks") | ||
); | ||
|
||
/* Adds the "resources/assets/example_mod/textures/blocks" | ||
directory as a source for the atlas. | ||
|
||
Adding "block/" at the start of every ResourceLocation's path. | ||
|
||
This will result in "example_mod:block/<my_block>". | ||
*/ | ||
gui.addSource(new DirectoryLister("blocks", "block/")); | ||
Comment on lines
+233
to
+245
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is still wrong. |
||
} | ||
} | ||
``` | ||
|
||
This new subclass of `SpriteSourceProvider` can then be registered under the `GatherDataEvent.Client` event: | ||
|
||
```java | ||
@EventBusSubscriber(modid = "example_mod", bus = EventBusSubscriber.Bus.MOD, value = Dist.CLIENT) | ||
public class DataGenerators { | ||
|
||
@SubscribeEvent | ||
public static void gatherData(GatherDataEvent.Client event) { | ||
|
||
DataGenerator generator = event.getGenerator(); | ||
PackOutput packOutput = generator.getPackOutput(); | ||
CompletableFuture<HolderLookup.Provider> lookupProvider = event.getLookupProvider(); | ||
|
||
// Registers the new `SpriteSourceProvider` | ||
// The fisrt parameter is `true` because Texture Atlases are client | ||
// resources and we know that this event is only fired for client resources | ||
generator.addProvider(true, new MySpriteSourceProvider(packOutput, lookupProvider)); | ||
Comment on lines
+263
to
+266
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would assume we recommend using |
||
} | ||
} | ||
``` | ||
|
||
[reg]:../../../concepts/registries.md | ||
[txtatlassource]:#texture-atlas-sources | ||
[spritesource]:#sprite-sources | ||
[resourceloc]:../../../misc/resourcelocation.md | ||
[spritesource_directory]:#directory-source | ||
[dtgn]:../../index.md#data-generation |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's not giving more control. The sprite sources quite literally determine what is within the final stitched texture.