A Godot 4.4+ tool for automatic baking of shader materials into images and packing them into Texture2DArray resources live in the editor (re-baking on every resource change), and optionally at runtime (generating arrays on scene play in build).
Baker nodes render shader parameters through a sub-viewport, store the resulting images, and notify the manager script.
Multiple categories (e.g. Albedo & Height, Normal & Roughness) can be defined in the manager, each using its own channel packing visual shader.
Baking is automatic — any change to shader parameters, including texture resources, triggers a re-bake only for the affected categories.
Generated arrays are synced to a shader, and pre/post-save hooks prevent in-memory resources (not saved to a .res file) from being serialized into the scene.
- Copy
material_bakerinto yourres://addons/, enable underProject > Project Settings > Plugins. - Add a MaterialBakerArrays node to the scene, load configs from
addons/material_baker/categories, otherwise give them a uniquebaker_category_uid. - Use the Create Material Baker button to add and auto-configure category configs and image settings, or duplicate existing baker nodes.
- Save arrays to
.resfiles and assign them as references to your shaders or useRuntimeShaderMapperto auto generate and sync arrays or textures to the shader at runtime. - Upon editing, the arrays are decompressed for performance, press Compress when done editing to reduce the
.resfile size.
Each MaterialBaker shows the shader parameters for every category directly in the Inspector.
NOTE: In the screenshot, albedo and height are packed to the same texture, so the channel is set to 3 which is Alpha (0123 => RGBA).
| Material Baker | Material Baker Arrays |
|---|---|
![]() |
![]() |
You can override each baker and each category with your own shader, see Bake Shaders section of the MaterialBaker node inspector.
NOTE: When using your own shaders note that the blend mode must be set to
premul_alphaso that alpha does not dim the color output.
Examples included under addons/material_baker/shaders/:
albedo_height_packer.tres— packs albedo (RGB) + height (A)normal_roughness_packer.tres— packs normal (RGB) + roughness (A)albedo_height_process_advanced.tres— showcases more complex tinting and contrast
Duplicate one of these and adapt to fit your texture inputs or to add custom image processing logic.
Basic albedo_height_packer.tres |
Advanced albedo_height_process_advanced.tres |
|---|---|
![]() |
![]() |
Compression is ignored during editing for performance and arrays are decompressed when bakers re-render on inspector changes.
Clicking the Compress button on the MaterialBakerArrays will apply the configured formats to the arrays.
Compression will persist if you save the arrays to a .res file, otherwise compression in build is not yet supported in Godot.
| Material Baker Image Settings | Material Baker Category Configs |
|---|---|
![]() |
![]() |
Mesh preview to inspect individual layers of the generated Texture2DArrays.
NOTE: In the demo scene the preview script has a signal connected to
RuntimeShaderMapper.mapping_appliedthat recreates the mesh when the arrays layer count changes.
Terrain3DMaterialBaker extends MaterialBakerManager and writes baked images into the Terrain3D texture list.
NOTE: You have to comment this out or focus loss breaks usage
asset_dock.gd:668 # plugin.select_terrain()
| Core | |
|---|---|
MaterialBakerArraysextends MaterialBakerManager |
Collects baked images from all bakers into one Texture2DArray per category. Has a ↓ Compress button to apply the configured compression format when ready. |
RuntimeShaderMapperextends Node |
Bridges a MaterialBakerArrays or MaterialBaker node to a ShaderMaterial at runtime. Maps each baker_category_uid to a configurable shader parameter name. Applies Texture2DArray outputs from MaterialBakerArrays or single ImageTexture outputs from MaterialBaker. On editor save, temporarily clears live parameters to avoid serializing in-memory resources into the scene file. |
MaterialBakerManagerextends Node |
Owns category_configs and image_settings, propagates them to MaterialBaker nodes. Has a + Create Material Baker button that adds a new baker with all the configs preconfigured. Override: baker_rendered, bakers_structure_changed, and regenerate. |
MaterialBakerextends ResourceWatcher |
Exposes all shader parameters for each category directly in the Inspector. Re-bakes automatically when resources change, and emits baker_rendered. Uses texture_hot_reload to swap external texture changes while Godot is not focused. |
MaterialBakerCategoryextends Node |
Internal renderer per category. Owns a SubViewport + ColorRect. Uses the category's shader, triggers a single-frame render, and returns the Image result. |
| Configs | |
|---|---|
MaterialBakerCategoryConfigextends Resource |
Shared definition for one baker category, e.g. Albedo & Height, Normal & Roughness.A unique baker_category_uid, a baker_category_label name and a default_shader. All bakers under the same manager reference the same config instances. |
MaterialBakerCategoryStateextends Resource |
Per-baker, per-category mutable state. See Bake Shaders to override with your own. The active Shader, its auto-managed ShaderMaterial, and a cache of the last baked Image. |
MaterialBakerImageSettingsextends Resource |
Output size, is_size_square, use_mipmaps toggle, and compress_mode format. Can be shared across all categories or set individually per category. |
| Utilities | |
|---|---|
ResourceWatcherextends Node |
Recursively connects to changed signal on all Resource properties (and their sub-resources). Batches notifications and calls on_resource_changed once per deferred frame. |
TextureHotReloaderextends Node |
Watches Texture2D parameters of registered ShaderMaterials for external file changes. Reloads textures via the reimport signal and also polls file modification times as a fallback. |
ShaderToPNGextends MaterialBakerCategory |
Bakes the shader material into a .png file, e.g., for channel packing after which you can discard originals. Optionally specify an existing .png whose import settings will be used for the generated one. |
- Arrays that are not saved to
.resfiles are auto generated upon entering the scene play. - This allows a game to ship with raw base textures and generate the rest asynchronously on the fly.
- Use
RuntimeShaderMapperto auto sync arrays or textures to shader parameters and have it prevent Godot from serializing in-memory resources into the scene. - Uncheck
generate_at_runtimeto disable and to also show warnings when.resfile array references are missing.
- Add more image processing examples, like auto generating a normalmap from a heightmap, or roughness from albedo
- Add example for caching runtime-generated arrays to .res files in build, e.g. ship without, generate once then reuse.
- Compression in build?
If you find an issue or have a use case that could be covered by this project, please open a new ticket or a PR.






