Skip to main content

XFSDK Texture Works

Demo​

Overview​

TextureWorks is an Unreal Editor texture-processing toolkit with four main operations:

  • Normal / Height - PBRify — generates Normal and experimental Height maps from Color / Albedo textures using the bundled PBRify models.
  • Normal to AO — generates texture-space visibility/AO from a tangent-space normal map using reconstructed, existing, or PBRify-predicted height data.
  • Normal to Curvature — generates signed curvature maps from tangent-space normal textures using GPU compute.
  • Texture Packer — combines channels from existing textures into configurable packed outputs such as ORD, ORM, ALBM, or custom layouts.

TextureWorks also provides bulk processing, reusable Profiles & Naming, configurable output suffixes, and shared settings across single and batch workflows.

All processing runs inside the Unreal Editor and produces regular Unreal texture assets that can be saved and used directly in your material workflow.

Requirements​

The standard From Normal and Existing Height Texture AO paths require:

  • A rendering GPU
  • SM5-capable compute shaders
  • Threaded rendering
  • A valid tangent-space normal map

No neural model is required for these two modes.

The experimental PBRify from Albedo height source additionally requires the PBRify Height model and Unreal's Windows NNE DirectML path.

Quick Start​

  1. Open Texture Works.
  2. Select the source Normal Map.
  3. Choose an appropriate Preset.
  4. Select the AO Height Source.
  5. Configure Wrap Texture for the source.
  6. Configure Flip Green Channel if required by the stored normal orientation.
  7. Leave Pack AO Into Mask Texture disabled for a standalone \_AO texture.
  8. Click Generate AO.
  9. Inspect the generated texture and save it in Unreal Editor.

AO Height Sources​

Texture Works supports three height-field sources.

Height SourceHeight DataRequired InputsHeight Iterations
From NormalReconstructed internally from the selected normalNormalEnabled
Existing Height TextureExisting linear height textureNormal + HeightDisabled
PBRify from Albedo (Experimental)Predicted internally using PBRify HeightNormal + AlbedoDisabled

From Normal​

This is the default deterministic workflow.

TextureWorks reconstructs a height field from the selected tangent-space normal map, then evaluates texture-space visibility over that reconstructed surface.

The method follows the material-surface occlusion approach described by Activision in:

The normal map is converted into surface slopes, those slopes are integrated into an approximate height field, and the resulting field is used for an orthographic GTAO-style visibility bake.

TextureWorks reuses UE5-style GTAO horizon-search and inner-integral concepts where practical, but it is not a byte-exact port of Activision's internal production tool or UE5's scene-depth GTAO pass.

The plugin removes scene-specific features such as camera projection, scene depth, HZB traversal, temporal filtering, and screen-space fade because the bake operates directly on texture data.

No standalone height texture is created by this AO operation.

Use Height Iterations to control the reconstruction workload.

caution

Activision's full material-surface occlusion model is broader than the baked texture generated here.

The TextureWorks output represents the texture-side visibility result. The plugin does not modify Unreal Engine lighting shaders to reproduce the complete Call of Duty material model, including direct micro-shadowing or indirect specular cone occlusion.

Existing Height Texture​

Use this when you already have an artist-authored, previously generated, or otherwise intended height map.

The height texture must:

  • Match the normal texture dimensions
  • Use supported source data
  • Have sRGB disabled
  • Represent linear scalar height data

Grayscale textures provide height directly. Supported color height textures use the red channel.

Invalid or missing height data causes the operation to fail rather than silently falling back to normal reconstruction.

PBRify from Albedo​

This experimental mode predicts height from a paired color/albedo texture using the PBRify Height model.

The selected normal is still required and continues to provide the normal-derived surface information used by the AO calculation.

The predicted height exists only for the current AO operation. No standalone height texture is created.

If you already generated a PBRify height texture using Normal / Height - PBRify, use Existing Height Texture instead to avoid running inference again.

Presets​

TextureWorks provides two AO starting presets.

PresetHeight IterationsAnglesTapsRadius PixelsEdge GuardHeight ScaleWrap
UV Atlas / Unwrapped6446628Off
Tileable Material6441224016On

Presets are starting points. Material scale, texture resolution, normal strength, UV layout, and intended appearance still matter.

UV Atlas / Unwrapped​

Use this for packed mesh textures and non-tileable UV layouts.

It uses:

  • A shorter AO search radius
  • Fewer taps
  • Wrapping disabled
  • Normal Edge Guard enabled

This reduces contamination between unrelated texture regions, but it cannot make separate UV islands behave as one physically continuous height field.

Tileable Material​

Use this for seamless textures where opposite texture borders represent continuous surface data.

It uses:

  • Texture wrapping
  • A larger search radius
  • More taps
  • Stronger height response

Do not use this preset blindly on packed UV atlases.

Settings​

SettingDescription
Height IterationsReconstruction work used only by From Normal. Higher values increase GPU work and may improve convergence.
AnglesNumber of AO search directions. Higher values increase sampling work.
TapsSamples taken along each search direction. Higher values increase sampling density and cost.
Radius PixelsAO search distance measured in source-texture pixels.
Normal Edge GuardPushes AO toward white around strong neighboring normal/slope discontinuities. 0 disables it.
Height ScaleScales the depth contribution of the selected/reconstructed height field.
Wrap TextureAllows sampling across opposite image borders. Enable for genuinely seamless textures.
Flip Green ChannelInverts the normal-map Y component during this operation without modifying the source texture.
Apply Albedo InterreflectionUses matching albedo brightness to approximate diffuse interreflection in the AO visibility result.
  1. Confirm the correct normal, dimensions, green-channel orientation, and height source.
  2. Choose the appropriate preset and boundary behavior.
  3. Tune Height Scale.
  4. Tune Radius Pixels.
  5. For packed atlases, adjust Normal Edge Guard.
  6. Adjust Angles and Taps only if more sampling quality is needed.
  7. Adjust Height Iterations only when using From Normal.
  8. Add Albedo Interreflection after establishing a useful baseline.

Change one setting at a time when comparing results.

Albedo Interreflection​

Apply Albedo Interreflection optionally modifies visibility using a matching-resolution albedo texture.

This is an artist-facing luminance approximation intended to reduce excessive darkening on brighter surfaces.

The output remains grayscale.

If the albedo is missing, unreadable, or the wrong size, optional interreflection is skipped.

**Note:** This option is separate from **PBRify from Albedo**. PBRify uses albedo to predict height, while Albedo Interreflection adjusts the resulting AO visibility.

Packing AO Into an Existing Mask​

Texture Works can write the generated AO directly into one channel of an existing mask texture.

This is separate from the full Texture Packer operation.

Enable:

Pack AO Into Mask Texture

Then choose either Quixel or Custom.

Quixel​

The Quixel preset:

  • Searches for \_ORD
  • Falls back to \_ORM
  • Writes AO into the Red channel

Custom​

Custom mode allows you to configure:

  • Mask Suffix
  • AO Channel: R, G, B, or A

The target mask must match the AO dimensions and use compatible BGRA8 source data.

The selected destination channel is replaced while the other source channels are preserved.

Successful packing changes the mask to linear mask compression and marks the existing asset dirty.

If AO insertion fails, TextureWorks attempts to create a standalone AO texture instead. Check the completion message and Output Log to confirm which output was produced.

Output​

Standalone AO​

Without mask packing, TextureWorks creates or updates a grayscale texture using the configured AO suffix.

Default:

Brick\_Normal → Brick\_AO

The stored values represent visibility:

1.0 = highly visible / unoccluded
0.0 = heavily occluded

Despite the \_AO asset name, the texture stores visibility rather than inverted occlusion.

Generated AO textures use:

  • G8 source data
  • Grayscale compression
  • sRGB Off
  • No mipmaps initially

Existing Assets​

If the calculated output name already contains a compatible UTexture2D, TextureWorks updates that texture.

It does not automatically create numbered duplicates or request overwrite confirmation.

Use another output suffix when you want to preserve multiple comparisons.

Generated or modified textures are marked dirty and must still be saved through Unreal Editor.

Standalone Height Generation​

Texture Works uses height internally but is not the standalone height-generation operation.

To create a reusable height texture, use Normal / Height - PBRify.

That operation supports:

  • Height prediction from Color / Albedo
  • Height reconstruction from an Existing Normal Map

You can then return to Texture Works and choose Existing Height Texture to use the saved result.

Artifact Mitigation​

Packed UV atlases can produce dark borders, dots, or halos because neighboring pixels in texture space may belong to unrelated parts of the mesh.

Recommended starting fixes:

  • Use UV Atlas / Unwrapped
  • Keep Wrap Texture disabled
  • Reduce Radius Pixels
  • Reduce Height Scale if the response is too aggressive
  • Increase Normal Edge Guard carefully
  • Verify the normal's green-channel orientation

**Important:** Disabling Wrap Texture only changes sampling at the outer image border. It does not detect or isolate internal UV islands.

Normal Edge Guard can reduce seam artifacts, but it can also suppress legitimate AO detail if pushed too far.

Tileable Materials​

For continuous repeating materials:

  • Start with Tileable Material
  • Keep Wrap Texture enabled
  • Tune Height Scale before increasing radius
  • Use larger radius/tap values only when broader cavity response is required

A texture should only use wrapping when opposite borders genuinely represent neighboring surface points.

Batch Conversion​

Multiple normal maps can be processed in one operation.

  1. Select two or more normal textures in the Content Browser.
  2. Right-click the selection.
  3. Choose Bulk Texture Works.
  4. Configure or load the intended shared settings.
  5. Inspect matched albedo/height inputs where applicable.
  6. Run the batch.
  7. Review processed and failed items.
  8. Save successful generated assets.

Bulk AO uses the same shared settings as single-texture AO.

Existing Height in Bulk​

When Existing Height Texture is selected, TextureWorks tries to locate a matching height texture for each normal.

Height matching checks the current configured height suffix and common aliases such as:

\_Height
\_Displacement
\_Disp
\_H

Inspect the matched-height list before starting the batch.

A missing required height causes that item to fail while other valid items can continue.

PBRify Height in Bulk​

When PBRify from Albedo is selected, each normal requires a readable, matching-resolution albedo.

A missing required albedo causes that item to fail without discarding successful results from other items.

Mask Packing in Bulk​

Bulk AO inherits the single AO panel's packing settings.

Configure the intended:

  • Packing preset
  • Custom suffix
  • Destination channel

before running the bulk workflow.

Each normal attempts to resolve its own mask texture. One manually selected mask is not reused for every material in the batch.

Normal Orientation​

AO reads the source normal pixels directly.

It does not automatically apply the Texture Editor asset's green-channel flip setting when reading those pixels.

If surface detail appears inverted:

  1. Test the normal in a material under directional lighting.
  2. Compare AO with Flip Green Channel disabled and enabled.
  3. Keep the interpretation consistent across AO, Curvature, and normal-derived height generation.

Avoid applying an extra flip to pixels that were already converted during PBRify output generation.

Troubleshooting​

AO or Curvature fails without a rendering GPU​

Use a normal Unreal Editor rendering session with SM5 compute and threaded rendering.

NullRHI and similar non-rendering environments cannot run this workflow.

Existing Height Texture fails​

Check:

  • Matching native dimensions
  • sRGB Off
  • Supported source format
  • Valid scalar data
  • Correct source texture

Height Iterations is disabled​

This is expected with:

  • Existing Height Texture
  • PBRify from Albedo

Only From Normal performs AO's internal normal-to-height reconstruction.

Dark UV-island borders​

Check:

  • UV Atlas / Unwrapped preset
  • Wrap disabled
  • Lower radius
  • Lower Height Scale
  • Normal Edge Guard

AO looks inverted or structurally wrong​

Verify the tangent-space normal convention and test Flip Green Channel.

Mask packing did not modify the expected texture​

Check:

  • Pack AO Into Mask Texture
  • Quixel/Custom preset
  • Destination channel
  • Selected mask
  • Matching dimensions
  • BGRA8 source data

A standalone AO may have been generated as fallback.

Batch height is not found​

Check:

  • Height is in the same material folder
  • Material basename matches
  • Configured Height suffix
  • Common height aliases
  • Bulk matched-height list

Current Limitations​

Texture Works is a texture-space process.

It does not:

  • Bake mesh geometry
  • Understand internal UV-island boundaries
  • Assign physical units to reconstructed height
  • Automatically create material instances
  • Automatically connect generated textures to materials
  • Automatically save dirty texture assets
  • Provide a dedicated cancellation control

The current release also does not automatically chain Normal, Height, AO, Curvature, and Texture Packing as one dependency graph.

References​

TextureWorks 2.3.1 includes:

  • Texture Works
  • Normal / Height - PBRify
  • Normal to Curvature
  • Texture Packer
  • Common Profiles & Naming
  • Bulk processing for all four operations

Use Profiles & Naming to keep generator suffixes, AO settings, packing recipes, and other shared settings consistent between materials and batch operations.