Skip to content

Textures & Materials

Fallout 4 uses two formats for surface data: DDS for texture images and BGSM/BGEM for material definitions that reference those textures and control shading parameters.

Material Organization

The material system in FO4 has four distinct concepts:

  • MaterialObjects are visual appearance presets referenced by objects in the ESM.
  • TextureSets (TXST records) contain the actual diffuse/normal/specular/glow/etc. texture paths.
  • MaterialSwaps (MSWP records) are runtime material substitutions that let variants of the same model render with different surfaces (see Material Swaps).
  • MaterialTypes (MATT records) define physics and surface behavior (footstep sounds, impact effects, friction, restitution) and are separate from the visual material system.

The two on-disk material file formats (.bgsm and .bgem) are referenced from NIF meshes and define shading parameters and texture slot bindings.


DDS (DirectDraw Surface)

Standard Microsoft texture format. FO4 textures are stored in BA2 archives as DX10-type entries (see BA2) and can also appear as loose files.

DDS File Header

magic          uint32   — 0x20534444 ("DDS ")
header_size    uint32   — 124
flags          uint32   — DDSD_* bitfield
height         uint32
width          uint32
pitch_or_linear_size uint32
depth          uint32
mip_map_count  uint32
reserved1      uint32[11]
pixel_format   DDSPF (32 bytes, see below)
caps           uint32
caps2          uint32
caps3          uint32
caps4          uint32
reserved2      uint32

When pixel_format.flags has DDPF_FOURCC and fourCC == "DX10", a DX10 extended header follows immediately after the main header:

dxgi_format    uint32   — DXGI_FORMAT enum
resource_dim   uint32   — 3 = texture2D
misc_flag      uint32   — 4 = cubemap
array_size     uint32
misc_flags2    uint32

Common FO4 Texture Formats

DXGI Format FourCC Use
BC1_UNORM (71) DXT1 Opaque diffuse maps
BC3_UNORM (77) DXT5 Diffuse with alpha
BC4_UNORM (80) ATI1 Single-channel masks (gloss, env mask)
BC5_UNORM (83) ATI2 Normal maps — stores X and Y; Z = sqrt(1-X²-Y²)
BC7_UNORM (98) High-quality RGBA (newer assets)
R8G8B8A8_UNORM (28) Uncompressed RGBA

Texture Slots (by NIF BSShaderTextureSet index)

Index Role Notes
0 Diffuse / albedo sRGB
1 Normal map BC5 XY; reconstruct Z
2 Environment mask Grayscale; controls env map intensity
3 Glow / emissive sRGB
4 Height / parallax Grayscale
5 Environment / cube map sRGB
6 Inner layer / backlight sRGB
7 Specular / smoothness Grayscale (R) + smoothness (A)

Texture Path Conventions

All paths in NIF and BGSM/BGEM files are relative to the Data\ directory:

textures\architecture\buildings\brickwall01_d.dds    ← diffuse
textures\architecture\buildings\brickwall01_n.dds    ← normal
textures\architecture\buildings\brickwall01_s.dds    ← specular/smooth

Common suffixes:

Suffix Meaning
_d Diffuse
_n Normal
_s Specular / smoothness
_g Glow / emissive
_e Environment map
_em Environment mask
_sk Skin
_p Height / parallax

BGSM — Bethesda Material (Lit Surface)

BGSM files define material parameters for geometry rendered with BSLightingShaderProperty. They are plain binary structs with a version prefix.

Extension: .bgsm — stored under Data\Materials\.

File Structure

"BGSM"        char[4]   — magic
version       uint32    — determines which optional fields are present
base_object   BGEM_Base — shared base class fields (see below)
[type-specific fields]

Base Class (BGSMBase) Fields

tile_u             bool
tile_v             bool
uv_offset_u        float32
uv_offset_v        float32
uv_scale_u         float32    — default 1.0
uv_scale_v         float32    — default 1.0
alpha              float32    — overall opacity, 0.0–1.0 (default 1.0)
alpha_blend_mode   uint8      — 0=None, 1=Standard, 2=Additive, 3=Multiplicative
alpha_test_ref     uint8      — cutoff threshold 0–255 (default 128)
alpha_test         bool       — enable alpha test
z_buffer_write     bool       — write to depth buffer (default true)
z_buffer_test      bool       — test against depth buffer (default true)
screen_space_reflections bool
wetting_occlusion_map    bool
decal              bool
two_sided          bool
decal_no_fade      bool
non_occluder       bool
refraction         bool
refraction_falloff bool
refraction_power   float32
environment_mapping      bool   — (v ≤ 2)
environment_mapping_mask float32 — (v ≤ 2)
grayscale_to_palette_color bool
mask_writes        uint8     — bitfield: ALBEDO=1, NORMAL=2, SPECULAR=4, AO=8, EMISSIVE=16, GLOSS=32 (v ≥ 6)

BGSM-Specific Fields

diffuse_texture              string
normal_texture               string
smooth_spec_texture          string
greyscale_texture            string
env_map_texture              string   — (v ≤ 2)
glow_texture                 string
inner_layer_texture          string   — (v ≤ 2)
wrinkles_texture             string   — (v ≤ 2)
displacement_texture         string
specular_texture             string   — (v ≥ 3)
lighting_texture             string   — (v ≥ 3)
flow_texture                 string   — (v ≥ 3)
distance_field_alpha_texture string   — (v ≥ 17)

enable_editor_alpha_ref      bool
translucency                 bool     — (v ≥ 8)
  translucency_thick         bool
  translucency_mixed_with_normal bool
  translucency_subsurface_color   Color3 (3× float32)
  translucency_transmissive_scale float32
  translucency_turbulence         float32
rim_lighting                 bool
rim_power                    float32
backlight_power              float32
subsurface_lighting          bool
subsurface_lighting_rolloff  float32

specular_enabled             bool
specular_color               Color3 (3× float32)
specular_mult                float32   — default 1.0
smoothness                   float32   — inverse roughness; 1.0 = mirror
fresnel_power                float32   — default 5.0
wetting_control_spec_scale   float32
wetting_control_spec_power   float32
wetting_control_spec_min_var float32
wetting_control_env_map_scale float32
wetting_control_fresnel_power float32
wetting_control_metalness    float32

pbr                          bool     — (v ≥ 3)
custom_porosity              bool     — (v ≥ 3)
porosity_value               float32  — (v ≥ 3)

hair_soft_lighting           bool
hair_softness                float32

emit_enabled                 bool
emittance_color              Color3   — (if emit_enabled)
emittance_mult               float32  — (if emit_enabled)
model_space_normals          bool
external_emittance           bool
lum_emittance                float32  — (v ≥ 12)
use_adaptive_emissive        bool     — (v ≥ 13)
  adaptive_emissive_exposure_offset  float32
  adaptive_emissive_final_exposure_min float32
  adaptive_emissive_final_exposure_max float32
back_lighting                bool
receive_shadows              bool
hide_secret                  bool
cast_shadows                 bool
dissolvefade                 bool
assume_shadowmask            bool
glowmap                      bool
environment_mapping_window   bool
environment_mapping_eye      bool

tessellate                   bool
displacement_tex_bias        float32
displacement_tex_scale       float32
tessellation_pn_scale        float32
tessellation_base_factor     float32
tessellation_fade_distance   float32

grayscale_to_palette_scale   float32
skew_specular_alpha          bool     — (v ≥ 1)

terrain                      bool     — (v ≥ 3)
  terrain_threshold_falloff  float32
  terrain_tiling_distance    float32
  terrain_rotation_angle     float32

BGEM — Bethesda Material (Effect Shader)

BGEM files define material parameters for geometry rendered with BSEffectShaderProperty. Used for particles, triggers, glass, atmospheric effects, and other non-standard surfaces.

Extension: .bgem — stored under Data\Materials\.

File Structure

"BGEM"    char[4]   — magic
version   uint32
base      BGSMBase  — same base class as BGSM
[effect-specific fields]

BGEM-Specific Fields

base_texture              string
greyscale_texture         string
env_map_texture           string
normal_texture            string
env_mask_texture          string
specular_texture          string   — (v ≥ 11)
lighting_texture          string   — (v ≥ 11)
glow_texture              string   — (v ≥ 11)

blood_enabled             bool
effect_lighting_enabled   bool
falloff_enabled           bool
falloff_color_enabled     bool
grayscale_to_palette_alpha bool
soft_enabled              bool
base_color                Color4 (4× float32)
base_color_scale          float32
falloff_start_angle       float32
falloff_stop_angle        float32
falloff_start_opacity     float32
falloff_stop_opacity      float32
lighting_influence        uint8
env_map_min_lod           uint8
soft_depth                float32
emit_enabled              bool
emittance_color           Color3   — (if emit_enabled)
emittance_mult            float32  — (if emit_enabled)
model_space_normals       bool
external_emittance        bool
lum_emittance             float32  — (v ≥ 12)
use_adaptive_emissive     bool     — (v ≥ 13)
  adaptive_emissive_exposure_offset  float32
  adaptive_emissive_final_exposure_min float32
  adaptive_emissive_final_exposure_max float32
effect_pbrspecular        bool

glass_enabled             bool     — (v ≥ 21)
glass_roughness_scratch_texture  string
glass_dirt_overlay_texture       string
glass_dirt_overlay_alpha         float32
glass_dirt_overlay_normal_strength float32
glass_fresnel_color              Color3
glass_refraction_scale_base      float32
glass_blur_scale_base            float32
glass_blur_scale_base2           float32

Alpha Blending Modes

Both BGSM and BGEM share the same alpha_blend_mode enum:

Value Mode Blend equation
0 None Opaque
1 Standard src_alpha × src + (1 − src_alpha) × dst
2 Additive src + dst
3 Multiplicative src × dst

Alpha testing (alpha_test = true) discards pixels where the alpha channel is below alpha_test_ref / 255.0, regardless of blend mode.


Greyscale-to-Palette System

Many FO4 diffuse textures are not color images — they are grayscale intensity masks that the runtime shader combines with a small color look-up table (LUT) to produce the final pixel color. Materials that use this path have a non-empty greyscale_texture field pointing to the LUT, grayscale_to_palette_color = true, and a grayscale_to_palette_scale modulator.

How it works at runtime

  1. The diffuse texture (e.g. bricks01_d.dds) stores only luminance information. Decoded RGB values look washed-out or purple/lavender because the DXT1 block colors are packed for indexing, not display.
  2. The LUT (e.g. Bricks01Grad01.dds) is a tiny uncompressed BGRA gradient — typically 32 × 128 pixels. Each row is one output color; rows are indexed top-to-bottom by luminance.
  3. For every rendered pixel the shader computes a perceptual luminance from the diffuse sample, converts it to a LUT row index, and reads the gradient color from the middle column of that row. That color replaces the sampled diffuse RGB.

LUT sampling

gray = int(0.299*r + 0.587*g + 0.114*b)         # perceptual luminance
row  = min(int(gray * 128 / 256), 127)           # map 0..255 → 0..127
color = lut[row]                                 # read middle column (x = 16) of that row

The LUT DDS is uncompressed BGRA, so its pixel data starts at byte 128 (after the 128-byte DDS header) and every pixel is 4 bytes in BGRA order.

Detecting palette-indexed diffuses

If a _d.dds decodes to an average purple/lavender hue (high R and B, low G) and its BGSM has a non-empty greyscale_texture, it is a palette source — do not treat the raw RGB as the final color.


Remap Textures

FO4's layered-material shader supports per-material color tinting through "remap" palette textures. Their filenames contain the token remap (e.g. ResidentialSidingRemap01_d.dds, RetailTrimRemap01_d.dds). Decoded directly, they appear flat purple/magenta because they store a tint palette, not a finished color image.

The non-remap sibling texture (same name with remap stripped — e.g. ResidentialSiding01_d.dds) is the properly colored base texture that ships alongside it.

To substitute a remap texture with its base version, strip remap from the filename only (leave the directory path intact). Only strip when remap is a standalone token — i.e. not followed by another letter — so names like remapped or remapping are left alone.


String Encoding in BGSM/BGEM

All string fields use a length-prefixed format:

length  uint32
chars   char[length]   — not null-terminated

An empty string has length = 0 with no following bytes.