# PBR Texture Baking Types and Workflows in ArmorPaint: A Complete Technical Guide

> Discover PBR texture baking types and workflows in ArmorPaint. Learn to generate essential PBR maps like Curvature, Normal, and AO using rasterization and GPU ray-tracing.

- Repository: [Armory 3D/armorpaint](https://github.com/armory3d/armorpaint)
- Tags: deep-dive
- Published: 2026-09-11

---

**ArmorPaint supports 14 distinct PBR texture baking types—from Curvature and Normal to Ambient Occlusion and Thickness—that generate physically-based rendering maps via both rasterization and GPU ray-tracing pipelines.**

PBR texture baking types and workflows in ArmorPaint enable artists to convert high-resolution sculpt detail and scene data into optimized texture maps for game engines. The baking system is implemented in the [armory3d/armorpaint](https://github.com/armory3d/armorpaint) repository and exposes these features through the **Bake Texture node** and the **Bake Material** menu interface.

## Overview of PBR Baking Architecture

The baking system in ArmorPaint distinguishes between **rasterized bakes** (geometry properties) and **ray-traced bakes** (lighting and occlusion). All bake types are defined as enumerations in [`paint/sources/enums.h`](https://github.com/armory3d/armorpaint/blob/main/paint/sources/enums.h) and processed through the **Bake Texture node** implementation found in [`paint/sources/nodes_material/bake_texture_node.c`](https://github.com/armory3d/armorpaint/blob/main/paint/sources/nodes_material/bake_texture_node.c).

Ray-traced bake types—including **Occlusion**, **Lightmap**, **Bent Normal**, and **Thickness**—require GPU ray-tracing support and utilize a dedicated pipeline in [`paint/sources/render/render_path_raytrace_bake.c`](https://github.com/armory3d/armorpaint/blob/main/paint/sources/render/render_path_raytrace_bake.c).

## Complete List of PBR Texture Baking Types

ArmorPaint defines 14 bake types covering geometric analysis, lighting simulation, and ID masking:

### Geometry and Surface Analysis

- **Curvature** (`BAKE_TYPE_CURVATURE`): Calculates convex and concave surface areas per texel to generate edge-wear masks.
- **Normal** (`BAKE_TYPE_NORMAL`): Transfers high-poly world-space normals onto low-poly UV layouts using RGBA128 format for precision.
- **Object Normal** (`BAKE_TYPE_NORMAL_OBJECT`): Stores object-space normals without world-space transforms, ideal for fixed-orientation assets.
- **Height** (`BAKE_TYPE_HEIGHT`): Encodes displacement data in the red channel to drive parallax occlusion mapping.
- **Derivative** (`BAKE_TYPE_DERIVATIVE`): Computes the slope/derivative of height data to capture fine surface detail.
- **Position** (`BAKE_TYPE_POSITION`): Bakes world-space XYZ coordinates into RGB channels for position-based shader effects.

### Utility and ID Maps

- **TexCoord** (`BAKE_TYPE_TEXCOORD`): Outputs raw UV coordinates for debugging or custom shader workflows.
- **Material ID** (`BAKE_TYPE_MATERIALID`): Assigns integer IDs per face based on material slot assignments.
- **Object ID** (`BAKE_TYPE_OBJECTID`): Encodes unique object identifiers for compositing and selection masks.
- **Vertex Color** (`BAKE_TYPE_VERTEX_COLOR`): Renders vertex color data into a texture format.

### Ray-Traced Lighting Bakes

- **Occlusion** (`BAKE_TYPE_OCCLUSION`): Ray-traced ambient occlusion (AO) that darkens cavities and contact shadows.
- **Lightmap** (`BAKE_TYPE_LIGHTMAP`): Bakes indirect global illumination into a static lighting texture.
- **Bent Normal** (`BAKE_TYPE_BENT_NORMAL`): Calculates AO-aware normals oriented toward open space to improve indirect lighting integration.
- **Thickness** (`BAKE_TYPE_THICKNESS`): Measures geometric thickness between front and back faces for subsurface scattering and translucency effects.

## Step-by-Step PBR Baking Workflow

The ArmorPaint baking workflow follows a six-stage pipeline controlled through the `Bake Texture node` and global context settings.

### 1. Select the Bake Target

Open the **Bake Texture** node or select **Bake Material…** from the main menu (defined in [`paint/sources/ui/ui_menubar.c`](https://github.com/armory3d/armorpaint/blob/main/paint/sources/ui/ui_menubar.c) at line 328). The node's UI, implemented in `bake_texture_node_button`, populates a combo box with available bake types. Ray-traced options only appear when `gpu_raytrace_supported()` returns true.

```c
/* UI population logic from bake_texture_node.c */
string_array_t *bakes = any_array_create_from_raw(
    (void *[]){
        tr("Curvature"), tr("Normal"), tr("Object Normal"), 
        tr("Height"), tr("Derivative"), tr("Position"), 
        tr("TexCoord"), tr("Material ID"), tr("Object ID"), 
        tr("Vertex Color"),
    }, 10);

if (gpu_raytrace_supported()) {
    any_array_push(bakes, tr("Occlusion"));
    any_array_push(bakes, tr("Lightmap"));
    any_array_push(bakes, tr("Bent Normal"));
    any_array_push(bakes, tr("Thickness"));
}
ui_combo(&bake_type, bakes, tr("Bake"), false, UI_ALIGN_LEFT, true);

```

### 2. Configure Bake Settings

For ray-traced bakes, configure **Samples**, **AO Strength**, **Radius**, and **Offset** through the node interface. These values are stored in the global context:

- `g_context->bake_samples` – Ray samples per pixel
- `g_context->bake_ao_strength` – Ambient occlusion intensity multiplier
- `g_context->bake_type` – Selected enum value from [`enums.h`](https://github.com/armory3d/armorpaint/blob/main/enums.h)

### 3. Initiate the Bake Process

When you click the **Bake** button (icon `ICON_PLAY`), the function `bake_texture_node_run` switches the active tool to `TOOL_TYPE_BAKE`, sets the context bake type, and initializes an RGBA32 render target (or RGBA128 for **Normal** and **Height** bakes requiring high precision).

### 4. Execute Ray-Tracing (When Applicable)

If the selected bake type requires ray-tracing, `render_path_raytrace_bake_commands` in [`render_path_raytrace_bake.c`](https://github.com/armory3d/armorpaint/blob/main/render_path_raytrace_bake.c) allocates three intermediate render targets (`baketex0`, `baketex1`, `baketex2`). The system dispatches rays iteratively based on `g_context->pdirty`, which tracks remaining samples.

```c
/* Ray-trace execution snippet from render_path_raytrace_bake.c */
if (g_context->pdirty > 0) {
    f32_array_t *f32a = render_path_raytrace_f32a;
    f32a->buffer[0] = render_path_raytrace_frame++;
    f32a->buffer[1] = g_context->bake_ao_strength;
    // Additional uniforms for radius, offset, etc.
    _gpu_raytrace_dispatch_rays(
        any_map_get(render_path_render_targets, "baketex2")->_image, 
        f32a
    );
}

```

### 5. Integrate Results into Layers

After completion, `bake_texture_node_check_result` replaces the active layer's `texpaint` texture with the baked output. The system automatically restores the original render-target format if temporary RGBA128 was used, and triggers UI redraws to display the result.

### 6. Post-Process and Export

You can now edit the baked map within the layer stack, blend it with existing textures, or export via **Export → Bake to Textures** for use in external game engines.

## Programmatic Control and Scripting

Developers can trigger bakes programmatically by manipulating the global context structure directly:

```c
/* Trigger a Normal bake from custom tooling */
g_context->tool      = TOOL_TYPE_BAKE;
g_context->bake_type = BAKE_TYPE_NORMAL;        // Select normal bake
g_context->pdirty    = g_context->bake_samples; // Initialize sample counter
make_material_parse_paint_material(false);        // Re-parse material for bake mode

```

For batch operations or automated pipelines, modify `g_context->bake_ao_strength` and other parameters before setting `pdirty` to initiate the rendering loop handled in [`render_path_paint.c`](https://github.com/armory3d/armorpaint/blob/main/render_path_paint.c).

## Summary

- **ArmorPaint provides 14 PBR texture baking types** defined in [`paint/sources/enums.h`](https://github.com/armory3d/armorpaint/blob/main/paint/sources/enums.h), ranging from geometric normals to ray-traced occlusion and thickness maps.
- **Two technical pipelines** exist: rasterization for geometry-based bakes and GPU ray-tracing for lighting-based bakes (Occlusion, Lightmap, Bent Normal, Thickness).
- **RGBA128 precision** is allocated automatically for Normal and Height bakes, while standard RGBA32 handles other types.
- **The Bake Texture node** in [`bake_texture_node.c`](https://github.com/armory3d/armorpaint/blob/main/bake_texture_node.c) orchestrates UI presentation, context configuration, and result integration.
- **Ray-traced workflows** utilize three intermediate render targets managed by [`render_path_raytrace_bake.c`](https://github.com/armory3d/armorpaint/blob/main/render_path_raytrace_bake.c) with configurable sample counts and strength parameters.

## Frequently Asked Questions

### What is the difference between Normal and Object Normal baking in ArmorPaint?

**Normal** (`BAKE_TYPE_NORMAL`) stores world-space normals relative to the scene coordinate system, which is essential for assets that rotate or move in game worlds. **Object Normal** (`BAKE_TYPE_NORMAL_OBJECT`) stores normals relative to the object's local coordinate system, making it ideal for static objects where the orientation never changes. Both use RGBA128 format for high-precision normal vector storage.

### Which PBR texture baking types require GPU ray tracing support?

The **Occlusion**, **Lightmap**, **Bent Normal**, and **Thickness** bake types require active GPU ray-tracing capabilities. These are conditionally added to the UI only when `gpu_raytrace_supported()` returns true, as implemented in the `bake_texture_node_button` function. All other bake types (Normal, Height, Curvature, etc.) work on standard rasterization hardware.

### How does ArmorPaint handle high-poly to low-poly normal map baking?

When you select **Normal** or **Object Normal** from the bake types, ArmorPaint uses the [high-poly mesh](https://github.com/armory3d/armorpaint) as the source for surface detail while projecting onto the low-poly UV layout. The system automatically creates an RGBA128 render target to preserve fine surface details without banding artifacts, then transfers the result to the layer's `texpaint` texture via `bake_texture_node_check_result`.

### What is the difference between Height and Derivative bakes?

**Height** (`BAKE_TYPE_HEIGHT`) stores absolute displacement values in the red channel, representing how much geometry protrudes or recedes from the surface plane. **Derivative** (`BAKE_TYPE_DERIVATIVE`) calculates the mathematical derivative (slope) of that height field, capturing surface steepness rather than elevation. Derivative maps are often combined with height data to improve bump mapping accuracy in shaders that calculate surface gradients.