Maturity: Draft. The resource model, template catalogue, G-buffer layout, deferred BRDF and the skin SSS pipeline are consolidated from source, installed resources and compiled programs. Runtime evidence is partial: the first photo-mode session (25 September) showed the colour shift working, distinct coverage steps, close-up breakup of a skin-coincident plate and uniformly glossy flat finishes; the second (26 September, partial) confirmed that the 0.4 mm plate lift removes the breakup (see in-game test asks, experiment 017 and experiment 020).
This page explains how Cyberpunk 2077 materials work well enough to:
- make the browser preview faithful;
- design makeup finishes that have a realistic chance of rendering correctly in game at the first attempt.
Hair is covered only at overview level here. See hair shading for the in-depth study.
Per-family references. The systematic shader study keeps one evidence-level reference per template family, with every parameter, pass, program hash and grade: skin, hair, eye, decals, multilayered and metal and glass. The shader fact index maps each engine fact to the Studio preview materials and export compilers that rely on it, so a correction reaches all of them.
Evidence grades:
- source: engine, framework or tool source, or disassembled compiled programs;
- resource: installed game or mod resources;
- wiki: Cyberpunk Modding Docs at commit
be2f44eed8419342ec13f72ed9cab008e9f7b289; - runtime: observed in the running game;
- hypothesis: not yet established.
Pinned sources:
| Source | Version |
|---|---|
| Installed game | 2.31 (GameVersion 2310 in serialized JSON) |
shader_ | SHA-256 339145…3ccfa |
staticshader_ | SHA-256 bff160…59ff |
| WolvenKit | CLI 8.17.4; source 11720772 |
| RED4ext.SDK | ad727771 |
| ArchiveXL | 5474e34d |
| Cyberpunk Blender add-on | 2.1.0 at 7a4ee793 |
| dxil-spirv / SPIRV-Cross (optional decompile) | f2d1b554 / aa217aeb |
Cyberpunk2077.exe / address library (§8) | SHA-256 a7de82…0991 / linker map 68af45ea |
| RED4ext (§8) | c52c8d80 |
Compiled-program hashes and the reproducible method are in the shader-system evidence note.
1. The material resource model
mesh (.mesh)
├─ appearances[k].chunkMaterials[submesh] ──name──► materialEntries[i] {name, isLocalInstance, index}
│ │ local │ external
│ localMaterialBuffer.materials[index] externalMaterials[index] (.mi path)
│ (embedded CMaterialInstance) │
└──────────────────────────────────────────────────────┴──► CMaterialInstance ── baseMaterial ──► (.mi …) ──► CMaterialTemplate (.mt/.remt)
sparse name→value overrides parameters, techniques/passes, materialType
1.1 Resource types
| Extension | RED class | Role | Grade |
|---|---|---|---|
.mt, .remt | CMaterialTemplate | The shader: typed parameters with defaults, compiled techniques and passes, render states, lighting class. Both extensions are the same class; .remt is used mainly by engine\ templates. | source WolvenKit FileTypeHelper.cs:284,296 |
.mi | CMaterialInstance | baseMaterial (a template or another .mi), a sparse values list of name → Variant, and enableMask. | source RED4ext N/; WolvenKit ClassesExt/ |
.hp | CHairProfile | gradientEntriesID and gradientEntriesRootToTip ({value, Color} stops), plus sampleCount | source G/ |
.sp | CSkinProfile | blurSize, diffuse, falloff, roughness0, roughness1, lobeMix | source G/ |
.gradient | CGradient | A list of colour stops, e.g. the eye IrisColorGradient | source G/ |
.mlsetup | Multilayer_ | An ordered list of Multilayer_, plus ratio and useNormal | source G/ |
.mltemplate | Multilayer_ | Colour/normal/roughness/metal textures, tilingMultiplier, and named override tables | source G/ |
.mlmask | Multilayer_ | Per-layer masks inside a render-resource blob | source G/ |
1.2 Parameter types
Template parameters are CMaterialParameter* objects with parameterName and register source (G/).
| Class | Value | References | Grade |
|---|---|---|---|
Scalar | float (plus min/max) | — | source |
Vector | Vector4 | — | source |
Color | Color (bytes); the program receives RGB sRGB-decoded and alpha as byte/255 (below) | — | source |
Texture, TextureArray, Cube, DynamicTexture | Ref<ITexture> | .xbm, .texarray, .cubemap | source |
HairParameters | Ref<CHairProfile> | .hp | source |
SkinParameters | Ref<CSkinProfile> | .sp | source |
MultilayerSetup, MultilayerMask | refs | .mlsetup, .mlmask | source |
Gradient | Ref<CGradient> | .gradient | source |
StructBuffer | none reflected | runtime data (multilayer Layers/MaskTiles) | source / resource |
How values reach the program [source: the 2.31 executable, research/]. The material constant-buffer packer (RVA 0x4ff4d4, called once per stage, vertex then pixel, by 0x1eb374) walks a layout of 4-byte entries (data offset, parameter type, register) and writes one float4 per register. The type is what each CMaterialParameter* class reports (its vtable slot 28): Texture 1, Color 2, Cube 3, Vector 4, Scalar 5, TextureArray 7, SkinParameters 10, HairParameters 13, Gradient 16, and so on. Color (4 bytes) becomes (srgb(R), srgb(G), srgb(B), A/255) through the engine's 256-entry sRGB-to-linear table, the same table the skin-profile colours and the debug-draw vertex colours go through; Vector is copied and Scalar broadcast to all four lanes; the resource types (Texture, Cube, TextureArray, SkinParameters, HairParameters, Foliage, Gradient) write an integer looked up for the bound resource (a texture index, and, by their use in the programs, the skin-profile slot and the gradient row [hypothesis for the meaning]). So a template that raises a Color to 2.2 itself (eye_'s ShadowColor) applies that power on top of the decoding. This covers material parameters packed by this routine; runtime overrides through other paths (scripts, effects) were not read.
WolvenKit maps each class to its value field in MaterialExtractor.cs:626-646. There is no .mltemplate parameter type. A template is reached only through Multilayer_ source.
Stage slots. parameters, usedParameters and samplerStates are three-slot arrays indexed like EMaterialShaderTarget: [0] unused, [1] vertex, [2] pixel.
- The indexing is source-supported:
G/, and WolvenKit reads only slot 2.EMaterialShaderTarget.hpp:12-15 - In every template inspected, vertex-animation parameters sit in [1] and all surface parameters in [2] resource.
usedParameters[2]gives the constant-buffer register the compiled pixel program uses (§3.1).
Wrong resource type or unresolved path renders black and shiny wiki (materials/ L17-25).
Inconsistent parameter names. The same concept has different names across templates (Albedo, BaseColor, DiffuseTexture, Color). Always read the template wiki (configuring-materials/ L82-88) resource.
1.3 How an instance chain resolves
| Rule | Grade |
|---|---|
| Defaults. The template's parameters supply the defaults. | wiki materials/ L35-42 |
Leaf wins. Each .mi applies its values over its base; the mesh-local instance is applied last. | wiki materials/ L35-42; source WolvenKit MaterialExtractor.cs:278-347 implements the same order |
| Undeclared names are inert. A value whose name the template does not declare has no effect. | wiki shaders/ L19 |
Unused names are dropped on export. WolvenKit only exports template parameters present in usedParameters[2]. | source MaterialExtractor.cs:389-424 |
Cycles crash the game. A cyclic baseMaterial chain does this. | wiki re-using-materials-.mi.md L29 |
Masking. Effective masking is template.canBeMasked && instance.enableMask. A masked draw uses the pass's stagePassNameDiscarded stage (…_); the shader cache records it as Discarded. In the decal and multilayered families a Discarded program is the plain program plus a per-draw temporal-dither dissolve driven by MaterialModifiersConsts[0].z/, not an alpha test on the texture's alpha; multilayered.mt has such variants although it cannot be masked. | source WolvenKit export logic MaterialExtractor.cs:313-314,386; the dissolve source (decal reference §2.3); which draws use it hypothesis |
Shared templates. Never edit a shipped template or a shared .mi: every user of it changes. About half the player head skin .mi files are shared with NPCs. | wiki configuring-materials/ L22-25; cheat-sheet-head/ L70-72 |
WolvenKit's material export applies this order for us. uncook … --mesh-export-type MeshOnly -gp <game> writes <mesh>.Material.json: every mesh-local material resolved through its .mi chain (Data holds the effective parameters), plus Appearances keyed <name><index> → chunk material names, and it decodes every texture those materials use. Example (2.31 female head, appearance default → 01_): Albedo h0_ and Normal h0_ come from the mesh-local instance, Roughness h0_ from default_ two levels up; a manual .mi walk gave the same answer. The Studio's derived preview reads this file instead of re-walking chains (src/). | resource 2.31 export, 25 Sep 2026, CLI 8.17.4 and 9.0.1; source MaterialExtractor.cs |
1.4 Mesh-side binding
Name lookup. chunkMaterials[submesh] names a materialEntries entry. That entry's isLocalInstance and index choose between two lists source:
- the local list,
localMaterialBuffer.materials(embedded CR2W files) orpreloadLocalMaterialInstances; - the external list,
externalMaterials(async.mirefs) orpreloadExternalMaterials.
ArchiveXL loads through exactly this pair (src/).
Unnamed chunks. A chunk without a valid material name renders invisible source (WolvenKit CMeshPreProcessor.cs:144-162).
Preload lists. Do not mix preload and non-preload lists of the same kind wiki (3d-objects-.mesh-files/ L230-241):
- mixing them makes non-preload materials render transparent on first use;
- WolvenKit's export also collides on names when the lists are mixed source (
MaterialExtractor.cs:223-271).
Dynamic materials (ArchiveXL) source (Extension.cpp, Dynamic.cpp):
- Template entries. A chunk name
prefix@tmplbinds to a template entry named@tmpl. - Soft references. Resource values and
baseMaterialpaths starting with*are soft and are substituted:{material}is the prefix;{material.N}is the Nth+-separated part;- other
{attr}tokens come from context attributes.
- Optional values. A trailing
?makes the value optional; if it is unresolved, the parameter is removed. - Base chains. Soft
.mibase chains are cloned recursively. @context. Local entry 0 named@contextsupplies override parameters and attributes.- Emulation gap. WolvenKit's
Material.jsonexport only emulates*and{material}source (ArchiveXlHelper.cs:14-61). Offline exports of CCXL-style chains can therefore silently fall back to defaults.
2. Rendering pipeline: what a material can and cannot express
2.1 Passes and render stages
Each template holds techniques[] → passes[]. A pass carries source (G/) resource:
- stage names (
stagePassNameRegular,stagePassNameDiscarded); - depth and stencil state;
- the rasterizer: cull, winding and
offsetMode, e.g.OFFSET_;DecalBias - per-target blend for up to 8 targets, with write masks;
enablePixelShader.
The depth test is GreaterEqual in G-buffer passes, i.e. a reversed-Z depth buffer resource.
Stage (renderstage_) | What it does, as evidenced | Examples |
|---|---|---|
gbuffer_ / gbuffer_ | Opaque G-buffer write, depth write on, no blending | skin, eye, metal_base, multilayered resource |
post_ | After the opaque G-buffer. Alpha-blends 3 targets with depth writes off. This is where decals live. | mesh_decal family, and metal_base has one too resource |
skin_ | Depth-only pass (pixel shader off, front-face cull, R write mask) that feeds the SSS/translucency pipeline | skin family resource |
hair_, hair_, hair_ | The three-part hair path (§4.3) | hair family resource |
transparent, transparent_, unlit, distortion | Forward passes after lighting, with their own lighting code | glass, eye_shadow, the clear-coat unlit pass resource source |
highlights | Outline and highlight buffer. Its programs write constants or zeros and compute no lighting. | nearly every template source particle-decal audit |
cascade_, depth, depth_ | Shadow and depth | resource |
The full stage list, with compilation counts, is in the local material-index.json produced by the evidence tool.
2.2 The G-buffer
The layout below is decoded from the tiled deferred light (m_) and from the skin, metal_base and mesh_decal writers. All of it is source (compiled programs; see the evidence note).
| Target | RGB | A |
|---|---|---|
| GBuffer0 | sqrt(linear base colour). The light squares it. | Class-specific payload (bits of the eye's second vector). Skin writes 1. |
| GBuffer1 | World normal n / max(|n|) × 0.5 + 0.5. The light uses normalize(rgb − 0.5). | Class-specific: skin-profile slot high bits (skin); tangent-axis selector (hair); octahedral bits (eye). 0 for metal_base. |
| GBuffer2 | x = metalness, y = roughness (the light clamps it to [0.04, 1]), z = a transmission weight: neutral 1/3 for Standard materials, 0.4 + 0.6·(vertex colour G) for skin. The deferred light reads it only for Foliage; the translucency variant of the SSS setup reads it for skin (sun transmission through thin parts). | Class-specific: skin-profile low bit, an emissive flag and 6 bits (skin); the eye's second vector (eye). Standard emissive writers (metal_base family, mesh_) store bit 7 = emissive flag and 7 bits = sqrt(EV/. |
| Stencil (bits 5+) | Lighting class = ERenderMaterialType: Standard 0, Subsurface 1, Cloth 2, Eye 3, Hair 4, Foliage 5. The value is set per material template (materialType). | — |
Grades for the less certain rows:
- Stencil-class identity: the enum values match the light's class switch and the templates'
materialType→ source/resource match. The actual stencil write was not traced → hypothesis. - GBuffer2.z: the all-classes global light (
…_,11111111 6606735909222169407) formssaturate((z − 1/(3) × 1.5) %85–%87) and uses it only in the Foliage branch (class 5, block%1051), as the weight of a back-lit transmission lobe added to diffuse (%1186–%1204); Eye forces it to 0. The Subsurface branch and the local-light path never read it (experiment 017). The SSSUseTranslucencysetup (11387959167119825062) does: for Subsurface pixels it adds a sun transmission term weighted by the samesaturate((z − 1/(for skin3) × 1.5) 0.1 + 0.9·G) and by a thickness falloff from a back-face depth target, before the blur source (skin reference §6.4). When that variant runs is hypothesis. The debug-view enumEEnvManagerModifierstill lists a "Translucency" view (G/); whether that view shows this channel is hypothesis.EEnvManagerModifier.hpp:24-40
Which templates carry which class resource:
| Class | Templates |
|---|---|
| Subsurface | skin, skin_, skin_, blackwall_ |
| Eye | the 6 eye templates (eye, eye_, eye_, eye_, blackwall variants) |
| Hair | the 6 hair templates |
| Foliage | speedtree and cloth_ |
| Standard | everything else (351 of 373), including every decal |
No template uses Cloth.
2.3 The deferred lighting model
Decoded from the global-light compute shader source:
| Term | Engine formula | Browser implication |
|---|---|---|
| Base colour / F0 | diffuse colour = albedo·(1−metal). F0 = lerp(0.04, albedo, metal). | Dielectric F0 is fixed at 0.04. No G-buffer channel sets IOR or specular level for non-metals. |
| Diffuse | Renormalized Burley (Disney) diffuse: fd90 = 0.5·r + 2·LdotH²·r, energy factor 1/. This is Frostbite's formulation (Lagarde & de Rousiers 2014). | Three.js MeshStandard/ uses Lambert. Rough skin and makeup darken or brighten differently at grazing angles. |
| Specular | GGX with α = roughness², height-correlated Smith visibility, Schlick Fresnel with F90 = 1 | Three uses the same α = r² convention. Roughness values transfer directly. |
| Sun / moon | A disk light, using the representative-point method | A small area light, not a point. Highlights on glossy makeup are slightly larger than a point light's. |
| Classes | Hair builds an anisotropic tangent frame. Eye decodes a second (iris) normal and has its own BRDF: Lambert diffuse on the iris normal, one GGX lobe on the cornea normal (GBuffer1) with its own visibility term and an exp2 Schlick Fresnel, no N·L on specular, a point sun, and ambient on the cornea normal; it switches off the GBuffer2.z term (eye rendering §3). Subsurface keeps diffuse and specular in separate outputs: albedo is set to 1 when metalness < 0.1 and a global flag is on, diffuse is Burley at the G-buffer roughness, and specular is two GGX lobes at roughness × roughness0 and × roughness1 from the pixel's skin-profile kernel (one of 8 slots, cb6 registers 4–11, SKernelDualSpecular), summed and scaled by (1 + lobeMix)/2. The default profile (roughness0 0.966, roughness1 1.597, lobeMix 1) gives skin up to twice a Standard lobe's specular. Local lights can also shift roughness per light: r′ = saturate(r + k·(byte/127.5 − 1)), from a byte of the light's parameters. source (…_ %575–%751, %2766 onward) | Skin roughness written by a decal does reach skin's specular. SSS is a separable screen-space blur of the diffuse irradiance (albedo 1), two passes (horizontal first is hypothesis), confined to Subsurface pixels: a neighbour counts only if it is class 1 and lit (red > 0), with no depth test, whole-pixel taps and per-channel renormalisation. The kernel is Jimenez et al.'s separable-SSS reference kernel over d'Eon and Luebke's skin profile, built on the CPU per profile: falloff sets each channel's width, blurSize scales the offsets, and the SubsurfaceScatteringQuality setting picks 11, 17 or 25 samples source (executable). The radius shrinks with depth; its absolute scale is hypothesis. The combine (7703933925853799832) lerps unblurred to blurred light per channel by the profile's diffuse colour, then multiplies by the pixel's albedo and adds specular unchanged, plus one term tinted by SubsurfaceSpecularTint. So skin detail and makeup colour stay sharp; only the shading softens. A pixel whose metalness exceeds 0.1 skips SSS entirely source (skin reference §6.3; the preview draws it the same way, §11). The global light has no probe term. The ambient (probe) composite is traced for the Eye class (eye reference §6.3) and for hair (hair reference §6.5); SSR and ray-traced reflections are not traced. |
Consequence (the central fact for makeup). The G-buffer stores one surface per pixel: one base colour, one normal, one metalness and one roughness. There is no clear-coat, sheen, second normal (except Eye), anisotropy (except Hair) or specular-tint channel. Anything that needs a second reflection lobe must come from a separate forward pass drawn after lighting. The stock examples are multilayered_'s unlit pass (dual-source blend One/) and eye_'s transparent_ pass (One/) resource source.
2.4 What a post_gbuffer decal does to the pixel under it
All source/resource (mesh-decal contract, evidence note):
- What it blends, and in what space. It blends base colour, normal and metalness/roughness into GBuffer0–2 with
SrcAlpha/. Each target gets its own alpha (colour, normal and surface coverage). Colour is written asInvSrcAlpha sqrt(colour), so decal colour blending happens in square-root (gamma-2) space, not linear. - Write mask RGB, stencil disabled. The decal never changes the lighting class, skin-profile slot or
.wpayloads. Makeup on skin is still lit as Subsurface skin. Metalness ≥ 0.1 on a Subsurface pixel takes the class's non-SSS albedo path (§2.3). - GBuffer2.z and skin translucency. The decal writes 1/3, so where surface coverage is non-zero it blends skin's
0.4 + 0.6·Gtoward 1/3. The deferred light ignores that channel for skin, but the SSS translucency setup weights its sun transmission by it, so a covering decal removes transmission under it source. The transmission needs thin geometry (a small front-to-back depth), so it matters on ears and nostrils, not under eye or lip makeup (skin reference §6.4). - Opacity curve. Coverage is
saturate((a−0.5)·tan((c+1)·π/. Each target's alpha multiplies it by4)+0.5)² · (1 − influence·secondaryMask) DiffuseAlpha,NormalAlphaorRoughnessMetalnessAlpha. All three default to 0, so an instance must enable them. - Placement and depth. Rasterizer state is front-face cull with CCW winding, which is equivalent to back-face cull with CW. The pass tests depth
GreaterEqualwithout writing it, andoffsetModeOFFSET_(value 3 ofDecalBias PSODescRasterizerModeOffsetMode) adds a depth bias whose values are engine-side and unknown.DepthThreshold(default 0.5) discards decal pixels farther than that from the scene depth; it does not settle coincident surfaces source. - Vanilla face decals do not rely on the bias. The 2.31 female eye-makeup, lip, freckle and pimple meshes are the head's vertices pushed 0.40 mm out along the head's normals (median residual 5 µm), and their morph targets keep the offset along each target's normal; they have one LOD like the head. The brow mesh is lifted 0.35 mm the same way (eyebrows). A plate coincident with the head broke into skin-coloured patches close up in photo mode, and was clean at medium distance resource runtime (first session, finish board results). XF Studio now lifts its packaged plate 0.4 mm the same way (experiment 017); in session 2 the 0 mm plate broke up again at an extreme close-up while the 0.1 mm and 0.4 mm lifts stayed clean runtime (experiment 020). The close-up-only mechanism (a depth bias that absorbs less world-space mismatch near the camera) is hypothesis.
3. Compiled shaders: finding and reading them
3.1 Where they are and how templates map to programs
| Cache | Contents | Grade |
|---|---|---|
PATH_ | All material-template programs. Footer RDHS v10. Programs are DXBC containers holding DXIL. Each compilation record reads <template> CompiledTechnique [Index, Pass '<stage>', PassIndex, …, RenderStageContext: [ID, VF: <factory>; Discarded/, followed by (vertex GUID, pixel GUID or none, material GUID). | source WolvenKit ShaderCacheReader.cs, with the stage correction below |
PATH_ | Engine programs: lighting, SSS, multilayer surface cache, hair resolve, post-FX, ray tracing. Footer RDHS v8, with m_ technique names. | source reverse-engineered here |
shaderps4/ | Console and Vulkan builds | not examined |
Stage labels. WolvenKit labels the first GUID "pixel". In all 19,647 records it is the vertex program; 2,564 records have no pixel program source.
Template-to-program link. Templates connect to programs only through a lookup key: the hashed template name plus a hash of the permutation (vertex factory and flags, technique index, render stage, pass index); see §8.1. No template field stores a shader GUID source. The name is the template resource's own CMaterialTemplate.name, not its depot path (three vanilla templates' names differ from their file stems, and the cache keys follow the name): a mod's copy of mesh_ at another path (the legacy XF generator's mesh_, identical to vanilla except materialPriority) keeps name = mesh_ resource and drew in game [runtime: the reference character wears the legacy build; no capture on file], so tools must identify a template by that name. The Studio's renderer does (head CC rendering §3). materialPriority is EMP_ (0) or EMP_ (1); serializers omit the default [source: WolvenKit RED4 enums].
Constant registers.
Material constants are
cb4, one register perusedParameters[2]register ([1] for vertex programs).- Each program keeps a
%ShaderSpecificConstantstype with one field per register:i32for Texture/TextureArray/Cube,floatfor Scalar,<4 x float>for Vector/Color. - Across one representative program per template, 314 of 314 checked templates agree, and no program reads a
cb4register that the template does not own source.
- Each program keeps a
Textures are bindless. The program loads an index from that
cb4register and indexest0, space1. Multilayer layer textures are the exception: their index comes from a structured-buffer load.Engine buffers keep their struct names in the DXIL resource metadata; their member names do not survive, so individual registers are identified by use source:
Register Struct cb0GlobalShaderConstscb1CameraShaderConstscb2ENV_PROBES cb3CustomPixelConsts/CustomVertexConstscb5FrequentVertexConstscb6COM/VER(static compute programs)cb7MaterialModifiersConstscb12SharedPixelConstscb13CSConstants
3.2 Repeatable method
research/ contains:
shader_(index / find / static / extract / summary);cache.py template_(parameters, registers, passes and blend states for all 373 templates);summary.py shader_(annotate, optionallyannotate.py --decompile/ search).
Recipe:
Serialize the templates with WolvenKit CLI 8.17.4:
unbundle memoryresident_, then1_ general.archive -r "\ .(mt|remt)$" convert serialize.Find the compilation with
shader_. The eye plate, head and eyes arecache.py find <template> --info "<stage>'.*VF: MeshSkinned\ ]" MeshSkinned.Annotate with
shader_. This extracts and disassembles with Windows SDKannotate.py annotate <template> --guid <pixelGUID> dxc -dumpbin, then writes readable pseudo-HLSL with names for:- template parameters and textures;
- engine struct names;
- the vertex inputs behind each interpolator;
- G-buffer and blend roles for each target.
shader_finds the programs that contain a code pattern.annotate.py search extractandsummaryremain for raw work.Read structured source if needed.
--decompileadds<GUID>.decompiled.hlsl: dxil-spirv (DXIL to SPIR-V) and SPIRV-Cross (to HLSL), both built from source, with the same names applied.- It gives real loops, typed values and a named per-register
cb4. HLSL output compiles withdxcfor 244 of 253 templates. - It is HLSL for about three quarters of templates; forward programs with wave ops or float-granular cbuffer views fall back to GLSL.
- Renaming was checked not to change the compiled program. The decompilers themselves are a second reading, not proof.
- Its
_are not SSA numbers (annotation results).N
- It gives real loops, typed values and a named per-register
Check against the disassembly (
<GUID>.annotated.ll) before relying on either listing. The lifted pseudo-HLSL folds expressions and keeps loops asgoto; it is a reading aid, not compilable source.Write it down. Record the program GUID, the SHA-256 and SSA ranges. SSA numbers are only valid within that one program.
Older one-off extractors (projects/, extract-brow-shader.ts, inspect-eye-skin-cache.ts, experiments/) cover the same v10 format for single studies.
3.3 Compiled-program index (MeshSkinned unless noted)
| Template / pass | Pixel GUID | Documented in |
|---|---|---|
skin gbuffer_ pixel / vertex (wrinkle regions) | 12806642364631437234 / 7494393843130164436 | skin reference, saved-skin trace |
eye gbuffer_ | 14845425953312192161 | eye reference, eye/lip optics |
eye_ gbuffer_ / gbuffer_ | 10020572278408962832 / 776001972724306108 | eye reference, exp. 014, eye rendering evidence |
mesh_ post_ | 16098255505177109230 | decal contract |
mesh_ post_ / vertex (byte-identical to the recolour-blendable vertex) | 3004271728282315156 / 13171349059403238141 | decal reference §5.2, glossy feasibility |
mesh_ post_ / its Discarded twin | 7624081209775720613 / 8834363738920290566 | decal reference §5.1 |
mesh_ / _ / _ post_ | 5232451138945967528 / 13292453303177655632 / 6714007623731301689 | decal reference §5.3 |
mesh_, _, _, _, _ post_ | 13887708964992876960, 12680699086337052733, 7449292646156817489, 6766005304427206345, 3236176651483732111 | decal reference §5.5 |
mesh_ post_ | 17388524518779931857 | glossy feasibility |
mesh_ post_ | 3456408455936683438 | colour-shift design, feasibility |
static m_ Setup / Setup_UseTranslucency / Blur_Horizontal / Blur_Vertical / Combine | 18323727242039837728 / 11387959167119825062 / 13638945895069409584 / 1061893983243070248 / 7703933925853799832 | skin reference §6, experiment 017 |
mesh_ vertex (Fresnel distance fade) | 7066617541061519457 (DXBC SHA-256 77e887ec…cb3) | colour-shift design |
mesh_ post_ / highlights | 1688064767334184205 / 10861674281505605668 | particle-decal audit |
mesh_ post_ (target 2 is additive on B/A, so over skin it would add into GBuffer2.z/.w [hypothesis for the visible effect]) | 9453098283293843067 | annotation results |
mesh_ subsurface_ / highlights | 8986576764202126900 / 7960168020925993542 | decal reference §5.4, glint feasibility |
metal_ gbuffer_ | 15760075574186250120 | glitter investigation |
metal_ gbuffer_ Index 1 / Discarded (alpha test) / Index 2 (weather) | 4684655453878116559 / 6427363791120029564 / 1846801220589112223 | metal and glass §3, evidence note |
metal_ post_ (decal mode) | 14174891702035234925 | metal and glass §3.5 |
glass_ transparent / distortion / transparent_ | 4256218839974653439 / 16640676567101803185 / 15548066001076791090 | metal and glass §4 |
static ambient and emissive composite (decodes the Standard emissive byte); the m_ technique (creator lighting §10.3) | 10393055107398307099 | metal and glass §3.6, eye reference §6.3 |
eye_ transparent_ | 14043594489545752539 | eye reference, evidence note, eye rendering evidence |
multilayered_ unlit / gbuffer_ (coat mask in GBuffer2.z) | 5403688829342147459 / 3911537533623547427 | multilayered reference §6, evidence note |
multilayered_ gbuffer_ (virtual-texture surface cache) | 9875025106086992270 | multilayered reference §7 |
multilayered gbuffer_ (MeshSkinned and MeshStatic) | 4792354088802328889 | multilayered evidence |
static m_ (compute) | 7318179378413828262 | multilayered evidence |
hair alpha_ / basecolor_ / gbuffer_ | 2782105832921211528 / 7571795766366002052 / 2903833597335136032 | hair reference, hair shading |
static m_ / _ (compute; _ holds the local-light hair path) | 10862954502888615639 / 6606735909222169407 | evidence note, hair reference §6.2 |
static m_ (compute) | 13401747477113664336 | evidence note |
static m_ (compute; PQ-space mean ± σ history clamp, 5 % blend) | 525406595650312948 | experiment 018 |
| static FSR2 / XeSS reactivity and DLSS colour-bias masks (compute) | 881371692195232951 / 15039989337359667650 / 7261057323686950841 | experiment 018 |
4. Template catalogue (characters and makeup)
Parameters and registers below are from the serialized 2.31 templates resource. Channel semantics are from compiled programs where cited source; everything else is marked. "Reg" is the cb4/usedParameters[2] register.
4.1 base\materials\skin.mt (and skin_blendable , skin_morph )
Class: Subsurface.
Passes: gbuffer_/velbuff (opaque), skin_ (depth only), cascade, highlights.
Vertex factories include MeshSkinned and the LightBlockers variants resource.
Every parameter, pass, program hash, the instance chains of the player head and body, and the full program walk-through are in the skin reference; the table below is the summary.
| Parameter (reg) | Semantics | Grade |
|---|---|---|
Albedo (0) | Base colour, UV0 | source |
Normal (4), DetailNormal (5), DetailNormalInfluence (6) | RG-packed tangent normals with Z reconstructed as sqrt(1−x²−y²). The detail normal (and the micro-detail) blend by slope-sum (partial-derivative) blending, lerped by influence | source |
Roughness (8) | R = base roughness. B gates a spatially varying bias between DetailRoughnessBiasMin/ (9/10), giving saturate(R·(1+B·(bias−1))), which is written to GBuffer2.y. G is written to GBuffer2.x, the slot the light reads as metalness, and also makes the pixel non-porous when wet. Vanilla head G is zero; a skin texture with G above 0.1 turns metallic and loses SSS. | source skin reference §4 |
MicroDetail (11), MicroDetailUVScale01/ (12/13), MicroDetailInfluence (14) | A 2:1 atlas of two micro-normal tiles at two frequencies, sampled with unwrapped derivatives; B of Roughness weights it | source |
TintColorMask (15), TintColor (16), TintScale (17) | Character-creator tone tint. Weight abs(TintScale)·Mask.R; a positive scale multiplies albedo by TintColor, a negative one overlays it. Mask G and B are microdetail selectors (tile blend and UV frequency), not tint. Per-tone values: head CC rendering §2 | source decompiled 12806642364631437234; wiki hair-and-skin-material-properties.md L28-38 (multiply only) |
SecondaryAlbedo (1), …Influence (2), …TintColorInfluence (3) | Overlay composited by Influence · SecondaryAlbedo.A, tinted toward the tone by TintColorInfluence; used by freckle and tattoo frameworks | source wiki |
SkinProfile (24) | Bound as a slot index 0–7 into a runtime table. The index is packed into GBuffer1.w and GBuffer2.w. The table holds each profile's dual lobe, its blur kernels (from falloff and blurSize) and its strength (diffuse); profile colours are sRGB-decoded on the CPU | source |
EmissiveMask (18), EmissiveEV (19) | Mask R × EV. If this exceeds 0.001, GBuffer2.w gets an emissive flag plus 6-bit intensity. | source |
CavityIntensity (7) | Strength of a small additive darkening from Roughness.B, the micro-detail term and the detail normal's red | source |
Detailmap_ (20/21), Bloodflow (22), BloodColor (23) | Wrinkle normals (RG) and a flush: BloodColor is added where Bloodflow.R × squash³ and Bloodflow.G × stretch³. The vertex program computes the two weights from UV-rectangle regions × animation float tracks (TextureRegionsCB, FloatTracksDataCB); both are 0 at rest. The regions are engine\: 33 stretch or squash regions named after the facial setup's 33 wrinkle outputs (natural expressions §9.3) | source; region set resource; that the engine feeds the solver's outputs through it hypothesis |
Vertex colour. The wiki reads vertex colour as R = AO, G = SSS mask and B = "improved facial lighting" wiki (shader-docs.md L47-51). The skin writer stores GBuffer2.z = 0.4 + 0.6·G: its vertex program passes COLOR.y straight through to the interpolator the pixel program reads source (annotation results). The deferred light ignores GBuffer2.z for skin (only Foliage reads it, §2.2); the SSS translucency setup uses it as the weight of sun transmission, which is consistent with the wiki's "SSS mask" reading source.
Wetness. With rain (MaterialModifiersConsts[3]), the program darkens porous (rough) skin and makes smooth skin glossier, strongest on up-facing surfaces, with drops, streaks and drips inside 60, 30 and 15 m; dry skin is unaffected source (skin reference §5.7). Outdoor test captures should record the weather.
Roughness under eye makeup. On the pale default head the Roughness map's R channel reads about 0.57–0.66 at the vanilla eye-makeup vertices (h0_, before the detail bias) resource (experiment 017).
No specular antialiasing. Neither the skin writer nor mesh_ derives roughness from normal-map variance. Decal textures are read with implicit-LOD Sample through one anisotropic, trilinear, wrapping sampler, so a texture's mip chain is the only filter a mod controls source (Glitter in game §1).
Gotcha. The Blender add-on maps Roughness G to Metallic and marks its microdetail masking as uncertain (material_). It uses Principled random-walk SSS, which is an approximation, not the engine path.
4.2 Eye family: eye.mt, eye_gradient.mt , eye_blendable.mt , eye_morph.mt
Class: Eye.
Passes: opaque G-buffer, velocity, cascade shadows (the eyeball casts sun shadows), depth, highlights and an editor pick pass; no translucency pass. eye.mt defaults: RoughnessScale 0.4934, RefractionIndex 0.97, EyeRadius 0.0152 resource. eye_ adds a braindance Fresnel rim to the colour and eye_ a scripted wipe of the gradient; otherwise the four share one arithmetic source (eye reference §2).
| Parameter | Semantics | Grade |
|---|---|---|
Albedo, Normal | Sampled at a computed, view- and eye-parameter-dependent UV. Normal is RG with reconstructed Z. | source optics audit |
Roughness | R × RoughnessScale, at the original UV, written to GBuffer2.y. The G channel is not used. | source |
NormalBubble, BubbleNormalTile | Cornea bulge normal (RG) | source |
IrisMask, IrisColorGradient (eye_) | The engine binds IrisColorGradient as a row index into a 512-row runtime gradient atlas, sampled at (mask R, (row + 0.5)/: mask R is the position along the row. Mask A lerps from Albedo to the gradient colour. | source exp. 014 |
RefractionIndex/, IrisSize, EyeParallaxPlane, EyeHorizAngleLeft/, Egg*, IrisCoord* | Parallax/refraction UV construction and the analytic cornea bulge. The index ratio 0.97 bends the view ray by about 1° at 30°, so the effect is nearly pure parallax 1.8 mm under a virtual 15.2 mm sphere | source (eye reference §5.3) |
Specularity | Written to GBuffer2.x, the metalness slot; 0 in every vanilla and inspected mod material | source |
Blick, BlickScale, SubsurfaceFactor, AntiLightbleed* | Read by no pixel program of the eye family in any pass or vertex factory, and by no static program. Blick is a cubemap. Inert in 2.31 unless a CPU-side consumer exists | source (eye rendering §2.4) |
Gotchas:
- The Eye class stores a second vector, the iris normal, octahedral-encoded to 10 bits per axis in GBuffer2.zw plus two low bits each in GBuffer0.w and GBuffer1.w; GBuffer1.rgb holds the cornea normal. It disables the translucency term (§2.3). The full program, the 71 creator colours and the preview spec are on eye rendering.
IrisMaskis a gamma texture, yet the gradient profiles are authored for its raw R range; the Rebecca eyes' normal map is a gamma texture too, and decoding its flat texels would tilt the iris normal 54° over the whole eye. Whether the engine decodes either is open (eye rendering §2.3).- Eye pixels are outside the SSS passes; the ambient pass multiplies their indirect light by
1 + cb6[9].wand can bypass their occlusion (eye reference §6.3–6.4). - The Blender add-on samples eye roughness G, contradicting the compiled R source. CCXL eye guides note the eye UVs are Y-flipped wiki (
ccxl-eye-textures.mdL267-271).
4.3 Hair (hair.mt family) — overview only
Class: Hair. There are three cooperating passes resource source:
hair_: alpha write mask only; alpha is accumulated atomically fromalpha_ accum Strand_R.Alpha hair_: additive; the two red-channel strand maps address a runtime gradient texture (the static cache names abasecolor_ blend HairProfilesGradientsresource).hair_: opaque, depth-writing.gbuffer_ solid
The light builds an anisotropic tangent frame for the Hair class. The sun and every local light use the same Karis-style model; only the intensity triple differs (cb0[12] for the sun, cb0[13] for local lights), and neither reads the Scattering thickness in GBuffer2.z source. .hp profiles hold two gradient ramps (gradientEntriesID, gradientEntriesRootToTip).
See hair-shading.md for the detailed formula work, the hair reference for the template, passes, lashes, cap and what still blocks correct hair colour, and the lash follow-up and hair-profile resolution.
4.4 eye_shadow.mt / eye_shadow_blendable.mt — the eye's occlusion and tear shell, not cosmetic eyeshadow
Class: Standard, EMP_.
Pass: transparent_, forward-lit, CULL_, blend One/, i.e. out = highlight + dst·alpha resource source.
Vertex factories: eye_ has MeshSkinned; eye_ has only MeshStatic and MeshExtSkinned resource. The blendable's pixel program is identical to eye_'s, and its Fresnel parameters are read by no program; it adds only a braindance glitch and fade on the vertex side source (eye reference §7.1).
| Parameter (reg) | Compiled semantics | Grade |
|---|---|---|
Mask (4) | R gives the shadow amount, saturate(Intensity·R^Exponent). G × WetnessRoughness gives a wet-highlight roughness in [0.04, 1]. B × WetnessStrength scales the lit highlight. | source |
ShadowColor (1), Exponent (2), Intensity (3) | Colour is linearized with exponent 2.2. Alpha darkens the destination toward the colour's luminance. | source |
WetnessRoughness (5), WetnessStrength (6) | Forward-lit specular added on top of already-lit pixels | source |
AdditiveAlphaBlend (0), SubsurfaceBlur (7) | Not read by this program | source |
Naming gotcha. This template's name refers to the ocular occlusion/tear film. The Blender add-on reads Mask R as alpha and A as coat, which does not match the program. The vanilla user is the player eye mesh's wetness chunk eyeWetness_ (eyeshadow_: ShadowColor 125,58,58, Intensity 0.7, Exponent 0.8; female chunk 2, male chunk 1) resource. Only the luminance of ShadowColor is used, the highlight has no Fresnel, and the probe contribution is multiplied by zero, so the shell adds no environment reflection source (eye rendering §4).
4.5 mesh_decal family (post_gbuffer , all Standard class, MeshSkinned available)
Common parameters. Every member shares DiffuseTexture/DiffuseColor/DiffuseAlpha, UV*, SecondaryMask*, NormalTexture/NormalAlpha/NormalAlphaTex/UseNormalAlphaTex/NormalsBlendingMode(+Alpha), RoughnessTexture/MetalnessTexture with scale and bias, AlphaMaskContrast, RoughnessMetalnessAlpha, Animation* and DepthThreshold resource.
Compiled contract for mesh_ source. Every program of the family, its passes and per-target blend states, and what each variant changes are in the decal reference:
- Normal is RG with reconstructed Z.
- Roughness and Metalness each read R × scale + bias, and they share one blend alpha (with GBuffer2.z): a decal cannot write roughness without also blending metalness towards its own value.
- Texture UVs are transformed by
UVScale/UVOffset/UVRotation(in half-turns) about 0.5 and then folded bysign·frac, so a UV window must keep the mesh inside one unit of the fold. - There are independent colour, normal and surface coverages. Colour and surface coverage are the squared contrast-adjusted colour-map alpha; normal alpha is not squared:
NormalAlpha× (UseNormalAlphaTex?NormalAlphaTex.R : colour-map alpha). NormalsBlendingMode> 0.5 loads the existing G-buffer normal and composes the decal normal with it by reoriented normal mapping (Barré-Brisebois & Hill) in the plate's tangent frame, lerped byNormalsBlendingModeAlpha.R (white by default). Its normal alpha is also multiplied bysaturate(50 − 50·z): a flat texel (z = 1) writes nothing, and full weight needs about 11.5° of tilt. Because the blend lerps the encoded normal, a partly faded facet keeps only about alpha × its tilt (a 5° facet keeps about 1°).NormalsBlendingModeAlphabelow 1 lerps towards the decal normal mirrored in X and Y, so it must stay white. Mode 0 replaces the normal with the plate normal plus the map at the plain alpha. source (decompiled16098255505177109230; see the Shimmer design and decal reference §4.5)
| Template | Distinguishing inputs | Relevance |
|---|---|---|
mesh_ | Base set | Current makeup export route resource |
mesh_ | Adds FresnelColor/Intensity/Exponent, VectorField, fade controls | mesh_ plus the same Fresnel colour and distance fade as the recolour-blendable template (byte-identical vertex program), but with squared coverage, the UV transform and per-texel base colour: a better host for Colour-shifting than the current route (decal reference §5.2) source |
mesh_ | Base set | Rain streaks: V scrolls with time. Writes surface alpha = 1.0 regardless of coverage. It would overwrite roughness across the whole plate. source |
mesh_ | GradientMap, UseGradientMap, SecondaryDiffuseAlpha/ | Brows and 36 of the 114 lip style options. Same outputs and UV transform as mesh_; coverage (p + (1 − p)·s·I)²; colour = powder term + saturate(GradientMapIntensity · gradient) × texture RGB, so at intensity 2 gradient channels above 0.5 clip; DepthThreshold defaults to 0 (no depth test) [source: pixel 7624081209775720613; 8834363738920290566 is its Discarded twin]. See hair shading and eyebrows. resource |
mesh_ | MaskTexture, GradientMap (or a .gradient in _). DiffuseTexture is an ID map indexing the gradient. | Recolour from one greyscale map: colour = DiffuseColor × gradient, linear, unsaturated coverage, no UV transform [source: 5232451138945967528]. _ reads the engine's runtime gradient atlas (the eye's) and raises all four channels to 0.45 [source: 13292453303177655632]; add-on meshdecal.py:53 |
mesh_ | Base = DiffuseColor × GradientMap(DiffuseTexture.R, 0.5); Fresnel colour × intensity × w × saturate(|1 − N·V|^exponent) added before the square root. Colour coverage = DiffuseAlpha × gradient alpha × MaskTexture.R, linear (not squared). The vertex program sets w = max(1 + MaterialModifiersConsts[2].x − saturate((d − FadeOutOffset)/FadeOutDistance), 0), d = horizontal camera-to-object distance; the defaults remove the tint beyond 0.7 m. | Colour-shifting export route, with the fade pushed to 1000 m source design |
mesh_ | HeightTexture, HeightStrength | A height-map ray search (linear march, then binary refinement) offsets every lookup: embossed depth for printed patterns; roughness and metalness raw R. The Blender add-on does not implement it. source |
mesh_ | DiffuseColor2, EmissiveEV, animation and scroll. Target 2 is additive (One/, write mask BA). | Glow accents, independent of light [source: 9453098283293843067]; over skin the additive write lands on the skin-profile and emissive bits, so the result there is not a clean emissive flag hypothesis (decal reference §5.4) |
mesh_ | EmissiveMask, EmissiveMaskChannel, EmissiveColor/. Stage subsurface_. | Emission only, no UV transform: colour = EmissiveEV × EmissiveColor (a plain multiplier, so EV 0 is black), opacity = MaterialModifiersConsts[2].x × mask, alpha-tested at AlphaThreshold [source: 8986576764202126900]. Whether that modifier is non-zero on a CCXL head component is hypothesis |
mesh_ | Flipbook atlas (plain mesh_ has the same time-driven flipbook controls) | The mesh_ arithmetic; not a glint model source |
mesh_, _, _ | Morph, reveal/flow, 8 tints | Scripted reveals driven by MaterialModifiersConsts[2].x, and eight per-vertex tints; all linear coverage source. Nothing for makeup |
2.31 has no mesh_ template (the 16 compiled templates are mesh_ plus _, _, _, _, _, _, _, _, _, _, _, _; the …_ name belongs to the braindance blackwall_); scars and face cyberware write their normals through plain mesh_ [source: installed shader cache index]. Every vanilla female face decal uses mesh_ or mesh_ resource.
4.6 Multilayered: engine\materials\multilayered.mt , multilayered_clear_coat.mt
multilayered.mt is Standard class. It is canBeMasked = 0, opaque and depth-writing, drawn in the depth prepass, with blending off on every target; its only transparency is the engine's whole-draw dissolve (§1.3) resource source. The game uses it for earrings and piercings, the 37 graphic eye designs, and most clothing, weapons and props. The family reference is the multilayered reference; line references are in the multilayered shader evidence.
Inputs:
MultilayerSetup(.mlsetup: an ordered list of layers, each naming a layer template,.mltemplate) andMultilayerMask(.mlmask: one mask per layer, stored as a BC4 tile atlas with tile tables) resource;GlobalNormalwith its intensity, UV scale and bias;- runtime-filled
MaskAtlas,MaskTiles,Layers(StructBuffers),LayersStartIndex,SetupLayerMaskandMask*dimensions source.
Evaluated per pixel source. The G-buffer program (4792354088802328889, one program for MeshSkinned and MeshStatic) loops over the layers at every pixel; it does not sample a cache. The static m_ compute program repeats the same arithmetic into cache pages, and the internal multilayered_ (9875025106086992270) reads them as a virtual texture (an indirection texture, 120-texel pages, a page-feedback buffer) source; when the engine switches a mesh to it is open. A variant pass adds rain and wetness on top at runtime; that is weather, not material. Layer textures are read with explicit gradients, and the normal and microblend gradients are scaled by NormalsTextureDDXYMultiplier / MicroblendsTextureDDXYMultiplier (default 1): a per-material mip bias for the maps that cause specular aliasing source (multilayered reference §5.4).
Layer values are name lookups. Each layer stores colorScale, normalStrength, rough/ as CNames that key into its template's override tables; its numeric fields are opacity, matTile, mbTile, microblend* and offsetU/ source (G/). The tables hold {n, v} entries; colour names are <hex>_ with null in either half, and null_/null are ordinary entries present in every vanilla template resource. Each template also has a defaultOverrides selection and colorMaskLevelsIn/. The wiki gives up to 20 layers wiki (multilayered/ L27, L80).
How the layers combine [source unless marked]:
| Step | Arithmetic |
|---|---|
| Order | Front to back: from the highest layer index down; the bottom layer (index 0) ignores its mask. A layer with no mask data at a pixel is skipped |
| Coverage | Mask m (bilinear, at frac(uv) with V flipped), crossfaded with the layer's microblend: mp = saturate(k + (m − k)·c), k = 1 − microblend.a; a = mp · opacity. c = 1 / microblendContrast [community + game capture; the CPU upload is unread]: a low contrast steepens the mask about k (the in-game ring eye designs need it, eye rendering §6.6) |
| Share | Each layer takes w = min(remaining, a) of the coverage still remaining. Not a lerp stack: two half-covering layers over a base give 0.5 / 0.5 / 0. Coverage left over is black, with zero roughness and metalness |
| Maps | Read at offset + matTile · frac(uv) (U times the setup's ratio) in the game's own texture rows; microblend likewise with mbTile |
| Roughness, metalness | The map's R through its levels as a clamped scale/bias chain: saturate(saturate(x·in₀ + in₁)·out₀ + out₁). The stored pairs are scale/bias (for example the input range 30…220 as (1.342, −0.158)) resource |
| Colour | colour map · lerp(1, colorScale, cm), where cm is the same chain on the roughness map through the template's colour-mask levels. Templates storing colorMaskLevelsOut = (0, 0) (most, including every earring template) must tint everywhere for vanilla gold and paint to look right; the CPU mapping is unread hypothesis |
| Normals | Layer normals add up by share; microblend normals blend in at the mask's edges (e = saturate(saturate(√(1 − 2·abs(mp − ½)))·opacity − Σa)); the two mix by the strongest microblend weight and are laid over GlobalNormal (strengthened by its intensity) with reoriented normal mapping |
| Output | GBuffer0 sqrt(albedo), GBuffer1 the normal, GBuffer2 (metalness, roughness, ⅓); roughness is clamped to [0.04, 1] only by the deferred light |
Colour maps are sRGB (isGamma), roughness, metalness, normals and microblends linear resource. How community tools differ (the Blender add-on stacks bottom-up with a lerp, ignores the colour mask, and writes the program's contrast form as saturate((m − (1 − c)(1 − a))/, the reciprocal reading; WolvenKit's preview paints flat colours) is recorded in the evidence note [community].
What the Studio draws. The preview's layered adapter (layered-material.ts) bakes this arithmetic once per material over the mesh's own UV range, accumulating in half floats, into two packed 8-bit maps (sRGB colour with roughness in alpha; the tangent normal with metalness in alpha) and lights them as a standard metal/rough surface. A bake is sized by texel density on the part's surface (about 20 texels a millimetre, 256–2048: a stud is 256², the eyeball 2048² as its UVs span several tiles), chunks with identical stacks and UV ranges share one bake, and a hidden slot is baked when first shown; five piercing chunks keep about 2 MiB of maps where they kept 160 MiB. Real-GPU tests match the bake to its CPU reference within one byte for constant and for tiled, offset, masked sRGB maps. It draws layered chunks on any slot whose render mask draws them in the scene: the V's piercings and the graphic eye designs so far (head CC rendering). The host clamps a setup's and a template's stored numbers to plausible ranges (a paint template's colour table holds up to 906 entries). A layer whose microblend is absent or unreadable is drawn over the values of base\ (RGB (126, 127, 255), alpha 104/255) and noted, not over alpha 1: under the reciprocal contrast, alpha 1 let a low-contrast layer cover every texel above its contrast [offline; what the engine does with a layer that names no microblend is unread]. The rendered look is hypothesis until an in-game comparison.
multilayered_ resource source:
- The G-buffer pass is opaque, depth-writing and Standard class. It also stores a per-pixel coat amount, the summed shares of the layers in
[CoatLayerMin, CoatLayerMax], as GBuffer2.z = 1/3 + ⅔·coat [source:3911537533623547427]. - A second
unlitforward pass, depth testEqual, blendsOne/(dual source): coat weightSrc1Color saturate((GBuffer2.z − 1/, adding a coat reflection (its own roughness ≥ 0.04 and Fresnel) and attenuating the base per channel [source:3)·1.5) × Opacity 5403688829342147459]. The coat therefore lands only on its own base pass's pixels (multilayered reference §6). - Parameters:
CoatTintFwd/,Side CoatTintFresnelBias,CoatSpecularColor,CoatRoughnessBase,CoatReflectionPower,CoatFresnelBias,CoatNormalStrength,CoatLayerMin/,Max Opacity. - A community test shows angle-dependent tint on a garment wiki (
multilayered-material-properties.mdL121-133, imageclearcoat_/1.png clearcoat_, discovered by Rebecca).2.png - Not an overlay: its base pass replaces the surface, and skin's Subsurface class with it.
Multilayered and makeup. On a face plate, any multilayered template would be an opaque Standard surface replacing the skin: no soft coverage, no SSS or skin lobes, no skin normal, black where no layer covers. Mixed finishes are already expressible per texel in a decal, which keeps the skin, and both are limited to one surface per pixel; the coat's second lobe cannot sit over skin. The makeup export therefore stays on the decal family source (multilayered reference §8).
4.7 engine\materials\metal_base.remt and glass_onesided.mt
Full reference: metal and glass. Both appear on arm cyberware (Gorilla Arms, Mantis Blades), the teeth mesh's unused default appearance, the accessories some CCXL hairstyles carry (earrings, hair pins) and many clothing items. The preview draws metal_ since 27 September (src/, without the alpha test yet); glass_ has no adapter.
metal_ is Standard class: a depth prepass, an opaque G-buffer pass (Index 1; Index 2 adds rain), and a post_ decal mode resource source.
- Inputs source:
saturate(BaseColor.rgb × BaseColorScale.rgb); metalness and roughness each from the R channel of their own map throughsaturate(x·scale + bias); an RG normal with Z reconstructed and XY ×NormalStrength; every UV ×LayerTileexceptEmissive. Defaults: grey colour, metalness 0, roughness 1, flat normal. - Output source: the plain Standard G-buffer (
sqrt(colour), the normal with.w0, metalness, roughness, 1/3), lit by the Standard deferred light and ambient composite (§2.3). Nothing about metal is special to the template: it is metalness and roughness. - Alpha test source: the Discarded variant discards where
BaseColor.a < AlphaThreshold(0.38) when an engine flag is set; the cyberware decal chunks setenableMask1 resource, and the wiki ties transparency toenableMaskwiki (textured-material-properties.mdL25); the link between them is hypothesis. - Emission source: only when
EmissiveEV > 0: the colour lerps towardEmissiveColor × BaseColorby the emissive mask, and GBuffer2.w stores a flag andsqrt(EV/in 7 bits,10) EV = max(log2(mask) + EmissiveEV, 0); the ambient composite adds the albedo times a per-frame function of it (2^EVif its constant is10·ln 2hypothesis).
glass_ writes no G-buffer. It is a forward transparent pass with dual-source blending, out = radiance + background × T per channel, plus a distortion pass and a transparent_ pass resource source:
- Transmittance
T = lerp(1, tint′·(1 − mask), Opacity), wheretint′isGlassTint × TintColordarkened and saturated toward grazing angles. It ignores the reflection's Fresnel source. - Reflection: F0 comes from
FresnelBias(0 → 0.25, 1 (default) → 0.08, 2 → 0.04), not fromIOR, which only the distortion pass reads. Roughness issaturate(GlassRoughnessBias + Roughness.R)(default 0). The environment term is Karis's analytic environment BRDF over box-projected probes; the direct term is a sun-only GGX lobe. The program has no local-light loop, so point, spot and photo-mode lights do not reflect in it source. - Distortion: active only when
IOR > 1orBlurRadius > 0. It adds a screen-space refraction offset (Snell's law 50 units along the ray, or a slab ofRefractionDepth) and a blur radius source. - Gorilla Arms glass sets
GlassSpecularColorto black: it reflects nothing, only tints (TintColor240, 235, 228), refracts (IOR1.32) and blurs (BlurRadius1) the mechanism behind it resource. glass.mtis the same with a back-face pass first (OpacityBackFace,BackFacesReflectionPower); its parameters are documented in wikiglass-material-properties.md.
Relatives:
pbr_has scalarsimple.mt Color,RoughnessandMetalnessonly resource.metal_is noise/time emissive, not a glint BRDF source glitter investigation.base_ glitter.mt metal_drives the Gorilla Arms thermal glow chunks (base_ blackbody.mt EmissiveEV10) resource; not read.
5. Texture conventions
| Convention | Evidence |
|---|---|
| Normal maps are two-channel (RG) with Z reconstructed in skin, eye, decal and multilayer global normals. Blue is ignored, and a DirectX orientation is expected. The compiled programs apply no Y flip, so orientation lives in the texture data. | source (compiled RG/Z paths); wiki normal-maps-in-cyberpunk.md L18-32, shader-docs.md L37-43 |
| Roughness and metalness are separate single-channel (R) maps in decals, with the usual meaning: white rough, white metal. Browser packed maps (G/B) must be split for export. | source decal contract; wiki textures/ L84-102 |
| Skin and eye roughness maps are multi-channel with template-specific meanings (skin R/G/B, eye R only). Three.js's default G sampling is wrong for both. | source |
Colour is stored as sqrt(linear) in the G-buffer. Whether a texture sample is sRGB-decoded depends on the XBM's isGamma / format. Diffuse maps use isGamma; normal and roughness maps are linear. Masks vary: the skin tint masks (h0_ and a texture framework's replacement) are gamma textures, so their R weight and G/B selector steps are sampled sRGB-decoded; the preview's skin adapter follows each resource's flag. | source (sqrt); wiki textures/ L60-62, ccxl-eye-textures.md L252 |
Textures are stored vertically flipped relative to PNG; WolvenKit's VFlip handles this. | wiki materials/ L28-29 |
Player head defaults. The female head mesh's own default appearance is the pale tone 01_ (D01 albedo). The eye mesh's default appearance is a metal_ placeholder on all three chunks; the real eye colour is an appearance the character creator selects (e.g. gradient_, whose albedo is he_ and whose colour comes from IrisColorGradient). | resource 2.31 h0_, he_ |
Gradient and profile ramps (.gradient, .hp) are baked at runtime into gradient textures that the shaders address by row. The .hp bake is decoded from the executable: stops sorted and rescaled to span 0–1, sampled at k/N, interpolated on the 8-bit values and truncated, then sRGB-decoded into float32 rows read unfiltered (hair shading §3). The .gradient rows' bytes and filtering are unrecovered. | source exp. 014, hair reference §7 |
6. Makeup finish implications
"Plate" means the owned morph-skinned eye-makeup mesh drawn over the head. Every decal route keeps the underlying Subsurface class (§2.4).
The Studio exports each preset as one decal draw, so per-texel inputs can vary within a preset but material constants cannot. The implemented routes are in finish-export.ts; each finish has a design page. None has been seen in game; the finish board is the prepared test.
| Finish | Export route (current) | Why / limits | Grade | Single confirming in-game test |
|---|---|---|---|---|
| Matte | Flat mesh_ (@preset): roughness 1.0 (0.88 until 27 September), metal 0, colour and surface alpha on, normal off | Replaces skin roughness under the mark (bare lid skin ≈ 0.6); skin SSS and skin's dual-lobe specular still apply. Its lobes are dimmer than bare skin's (they were at 0.88 too), so its written roughness cannot make it read glossier under direct light; vanilla matte lipstick writes the same 1.0, at 35–40 % weight. | source route; runtime read glossy on the first board (with close-up breakup) | Experiment 017 Gloss A–D |
| Satin | Same, roughness 0.38 | Glossier than bare lid skin (≈ 0.6) and than vanilla eye makeup (0.50), and skin doubles the lobe; a calibrated 0.50 is on the next candidate | source; look hypothesis | Experiment 017 Gloss D against Gloss A |
| Metallic / foil | Same, roughness 0.27, metal 0.65 | At metal ≥ 0.1 the Subsurface class leaves its SSS albedo path. Reflections come from probes/SSR/RT, so metallic looks dark in dim or probe-poor scenes. Losing SSS also makes the skin under it read hard. | source; runtime part of the uniformly glossy first board | Experiment 017 Gloss A–D (right outer stripe); Metal ramp · lifted for the 0.1 seam |
| Glossy / wet | Experimental. Flat mesh_, one dielectric lobe at roughness 0.12 (game-matched model only) | One G-buffer lobe: no clear coat, same F0 as skin, only sharper. The eye_ forward shell (Intensity 0, wet highlight from Mask G/B) remains the only stock way to add a second lobe; not built. | source; look hypothesis; runtime not distinct from Satin on the first board | Experiment 017 Gloss A against Gloss D (0.24) |
| Shimmer / pearl | Experimental. mesh_ in NormalsBlendingMode 1 (@faceted): a uniform surface (roughness 0.32, metalness 0.3, a pigment-tinted lobe) and a one-texel grain of tilted normals (about a quarter of texels at 12° or more, the rest flat), roughness mips widened by the grain variance lost to averaging (Shimmer design) | Every tilted grain clears the ≈ 11.5° mode-1 gate; flat texels leave the skin normal. Nothing static varies between texels, so any pattern must move with the light. At face framing grains are sub-pixel and the chain turns them into a broader, brighter lobe; close up they glint individually. Random azimuths make the untested green sign irrelevant statistically. | source; [offline] experiment 030; runtime the facet bake it replaced read as a diffuse gloss by default and, at Shimmer · strong, as a static regular grid of oversized dots (per-facet metalness in 1.2–3.5 mm discs on a UV-cell lattice); the grain has not been in game | Shimmer grain check: Shimmer · strong rebuilt with the grain |
| Glitter | None (preview only). Proposed: resolved glint flakes in mesh_ through a plate-local UV window (4096×1024), with nested flake mips; fallback adds an emissive accent chunk (Glitter in game) | No stock glint BRDF; one normal per pixel, no specular antialiasing, and a temporal clamp that removes one-pixel glints, so flakes must stay ≥ 2 texels wide at every mip. Board 2's coarse stripe was ~5.6 mm facets (sequins), not a glitter test. The accent's template multiplies its colour by EmissiveEV directly (0 is black; the diagnostic board writes 1 since 27 September) and gates it by an engine modifier (decal reference §5.4). | source; route measured [offline]; look hypothesis | Experiment 018 Glitter A and B |
| Colour-shifting | Experimental. Per-preset mesh_ (@fresnel_): uniform base-colour gradient, linear coverage mask, roughness 0.32 and metal 0.08 via bias (0.25 until 27 September), FresnelColor from the chosen shift colour, exponent 2, distance fade pushed away | One additive secondary hue by view angle, lit like base colour; not thin-film or multichrome. One constant per draw, so a colour-shift preset must be one pigment. At metalness 0.08 the covered skin keeps its SSS at any coverage (0.25 crossed the 0.1 switch at 40 %, Metallic's hardness); the tint itself needs no metalness. FresnelColor is written sRGB-encoded, since the engine decodes Color parameters (§1.2); MaterialModifiersConsts[2].x is unconfirmed. | source; look hypothesis | Boards 3 and 4: teal at the lid edges that follows the camera, not the light |
Plate depth. Every route draws on the plate lifted 0.4 mm off the skin, like the vanilla face decals (§2.4 item 6).
Plate texel density and the UV window. The plate keeps the head's UV0, so a head-atlas texture spends only a 0.453 × 0.145 rectangle on it: at 1024 a texel is about 0.56 × 0.40 mm on the lids (569 and 405 mm per UV unit, area-weighted medians). The vanilla eye-makeup mesh has its own UV layout at about 66 mm per UV unit, so its 1024 texels are 0.065 mm resource (experiment 018). mesh_ transforms every texture UV by UVScale/UVOffset from the UV as stored in the mesh source, so Build now maps just the plate's rectangle onto a 2048 × 512 texture for the flat and faceted routes: about 0.13 × 0.12 mm per texel at today's texel count and memory [offline]. The V sign follows from two offline facts: the Studio authors in glTF UV (1 − stored V), and WolvenKit's XBM import stores image rows bottom to top; so UVOffsetY is negative (−1.66 for the built-in plate) and the verifier checks the stored row order on every build. The Fresnel route's gradient-recolour template has no UV transform and stays on the 1024 head atlas. The window's placement has not been seen in game (experiment 019). Shimmer's grain is one texel of this window (0.13 × 0.12 mm).
Calibration against skin. Finish roughness sits on top of skin, not a Standard surface: skin's own roughness under the lids is about 0.6, vanilla eye makeup writes 0.50 at full surface alpha (and breaks its coverage with a ×30 noise mask), and the Subsurface class sums two GGX lobes at 0.97× and 1.6× the written roughness. On the first in-game board, Matte, Satin, Glossy and Metallic read uniformly glossy; experiment 017 separates "values too glossy" (Gloss D: all +0.12) from "written roughness not what you see" (Gloss B: surface alpha 0; Gloss C: roughness forced to 1) [hypothesis until that session]. CDPR's own makeup gives the calibration points resource: eye makeup 0.50 at full surface weight with noise-broken coverage, matte lipstick roughness 1.0 at 35–40 % weight, glossy lipstick keeping the skin's roughness (plus metalness 1 at 5 %), gold and silver blush metalness 1 at roughness ≈ 0.51 (if its sRGB-flagged roughness texture is read raw; ≈ 0.22 if decoded, face makeup open question 1). None of them writes one constant roughness at full weight over a whole mark, as the flat route does; that uniformity, which replaces the skin's pore-level roughness variation, is the decal-side suspect for the "plastic" read (decal reference §9.1) hypothesis.
What the preview predicts for Board 1 [offline; approximation of the light]. Since the authored plate is lit once with the skin's light (head CC rendering §3), Board 1 in the preview (default V, reference profile, both lighting presets, three studio key angles) reads much closer to the in-game report than before. Metallic becomes a bright, pale, sheet-like reflection as bright as the bare lid skin at the same pixels (0.89–1.12 of its median luminance, from 0.37–0.41) with 2.7–4.7 times the skin's highlight: at metalness 0.65 the reflection takes F0 from the pigment through skin's two summed lobes, and the SSS stand-in is off. Glossy shows 1.1–4.9 times the skin's highlight (0.5–2.3 before), and Satin about the skin's own (1.0–1.2), so it does not read as satin. Matte does not read glossy (at or below the skin's highlight), so the light alone does not explain the in-game report for Matte; the close-up breakup and the photo-mode per-light roughness shift remain the suspects there. With Gloss D's values (all +0.12) the preview lowers highlight peaks by 15–30 % on Satin and Glossy and Metallic's highlight by about a quarter, but moves the broad sheen by under 10 % and leaves Metallic as bright: D alone is not predicted to make the board read matte and satin, and for Metallic the metalness is the larger lever. Statistics are per-stripe percentiles of private captures (tools/); the in-game Gloss A–D frames decide.
Cross-cutting guidance for the browser preview:
- Blend decal colour in sqrt space, and apply the decal's squared coverage curve. The preview does, for the V's own face decals and for the authored plate, whose layers blend as the export's one merged decal (head CC rendering §3).
- Use F0 = 0.04 for non-metals, and treat roughness as perceptual (α = r²).
- Light makeup on skin with the skin's light: renormalised Burley diffuse and the profile's two lobes, once, on the blended surface. The preview does for the skin, the face decals (per pass) and the authored plate (once, on the blended surface; head CC rendering §3).
- Present Glossy as the one lobe the game can draw (the game-matched model does); a clear coat would need a second, forward pass.
- Sample skin roughness from R, with B gating the bias, and eye roughness from R × scale.
7. Open questions
These become backlog items.
GBuffer2.z for skin.Answered source: the SSS translucency setup (11387959167119825062) weights a sun transmission term by it; the static index's other GUID under that name (2220067148481019988) is a sun-light program. Still open: which setting enables the translucency variant, and what its camera vector and per-pixel factor are (skin reference §6.4).- Stencil write. Confirm that the engine writes
materialTypeinto stencil bits 5–7, via a runtime capture or the pass stencil setup code. - Skin-profile table. The table holds 8 slots per frame;
roughness0/and1 lobeMixform the dual-lobe specular kernel (§2.3), and the CPU builds each slot's blur kernel and strength fromblurSize,diffuseandfalloff(answered source: skin reference §6.3.2). Open: the kernel's absolute screen scale; whether the separable or the stochastic blur runs at a given setting; what happens with more than 8 distinct.spon screen; which lights set the per-light roughness byte, and to what (photo-mode lights in particular). - Metal ≥ 0.1 threshold. The SSS blur and combine skip pixels whose blended metalness exceeds 0.1 source; the flag controlling the light's albedo = 1 path is unknown. Does metallic makeup over skin show a visible SSS seam at soft edges (the lifted metal ramp on the next candidate)? The preview switches its SSS stand-in off on the authored plate's blended metalness, so Metallic crosses it at about 15 % coverage over dielectric skin; the albedo = 1 path is not modelled.
Eye second vector.Answered source: it is the iris normal from theNormalmap at the refracted coordinate; the light uses it for Lambert diffuse and the specular horizon, and the cornea normal for specular and ambient. No program readsBlick,SubsurfaceFactororAntiLightbleed*. Remaining eye questions are on eye rendering.eye_as a gloss shell. Is it usable as a glossy-makeup shell (sorting,shadow transparent_stage semantics, blink, cost)? (Its vanilla user is the eye mesh's wetness chunk.) Known from the programs: onlyback_ face eye_itself compiles for MeshSkinned; withshadow Intensity0 it adds a direct-light-only GGX highlight with no Fresnel and no environment reflection, so a wet look would show only under direct lights (eye reference §7.2).- Runtime gradient atlases. Recover the
.gradientatlas construction (row assignment, colour space, filtering, and whether stops are rescaled like.hp). This affects the gradient eyes andmesh_. Thedecal_ gradientmap_ recolor_ 2 .hpbake is decoded (hair reference §7); brows sample an ordinary gradient texture, not an atlas (eyebrows). A clue:mesh_reads the eye's atlas and raises all four channels, alpha included, to 0.45, which suggests the atlas stores its channels with a 2.2 power (decal reference §5.3).decal_ gradientmap_ recolor_ 2 - Unmapped debris. Recover the G-buffer render-target formats (8-bit vs 10-bit precision affects the sqrt encoding) and the meaning of the low 5 stencil bits.
- Ray-tracing libraries. Parse the ray-tracing libraries in
staticshader_. Their names survive (final.cache ShadeSurfaceWithLightSample*,GBuffer0..2), which could confirm the BRDF and G-buffer semantics independently. Multilayer levels.Answered source: the pairs feed a clamped scale/bias chain (saturate(saturate(x·a + b)·c + d)), identical in the G-buffer and surface-cache programs. For multilayered, game captures of the ring eye designs now support two CPU mappings:microblendContrastenters as its reciprocal, andcolorMaskLevelsOut = (0, 0)tints (the ring's red comes from a template storing (0, 0)) [game capture, 27 September 2026, eye rendering §6.6]. Still open: whethercolorScaleis linearised andmatTilemultiplied bytilingMultiplier, and when the surface cache is used (evidence).Answered: sRGB-decoded RGB, linear alpha [source; runtime-supported]. The executable's material constant-buffer packer converts everyColorparameter encoding.Colorparameter's RGB through the engine's sRGB-to-linear table and its alpha as byte/255 (§1.2). Session 4's skin-tone frames agree: senna amber and limestone against warm ivory darken the skin more than byte/255 can at full mask weight, and limestone's blue-to-green ratio rises where byte/255 must lower it; the sRGB fit holds even with a free tone-curve exponent per region [runtime, provisional: Ultra+'s RT skin tuning was on and the frames are display-referred; experiment 029 §4.2]. The preview decodes everyColorit reads this way (skin and teethTintColor, decal and brow colours, the eye shell'sShadowColorbefore its own 2.2 power), and the Colour-shifting export writesFresnelColorsRGB-encoded. Still open from the old question: what isMaterialModifiersConsts[2].xon the player head? It also gates the opacity ofmesh_(the glitter accent), anddecal_ emissive_ subsurface [0].z/drive the Discarded dissolve..w - Debug views. Can the engine's
EEnvManagerModifierdebug views (G-buffer, Roughness, Metalness, Translucency, MaterialID) be enabled from CET or RED4ext? That would turn most questions here into one capture session. - Decal depth bias. What depth bias does
OFFSET_apply, and does it explain why a coincident decal failed only close up?DecalBias - Temporal filtering and upscalers. Which program is the main anti-aliasing? Does the engine apply a negative texture LOD bias under DLSS, FSR3 or XeSS? How do the upscalers treat stable 2–3 pixel glints? Tracked in Glitter in game.
- Decal normal source. A mode-1 decal composes with a copy of the G-buffer normal (
t74). Is it refreshed between decal draws, so that overlapping normal-writing decals compose with each other rather than with the skin (decal reference §4.5)? - Glass and local lights. The
glass_transparent program reflects only the sun and the probes; it has no local-light loop source. Confirm with a photo-mode light moved across the Gorilla Arms window, and settle what enablesonesided metal_'s alpha-test variant and itsbase post_pass (metal and glass §8–9).gbuffer
8. Custom shaders: from template to pipeline state
How the engine turns a material template into GPU work, for the XF Shaders track (our own material shaders). Everything here is offline evidence from the 2.31 executable, CD PROJEKT RED's address library and the cache file; the full trace with addresses, IDs and grades is the pipeline trace, and exe_ re-proves it. Nothing is confirmed in game yet; the probe plan is the test.
8.1 How a technique is found source
- One cache, one lookup key.
shader_is opened once at start-up; only itsfinal.cache RDHSmagic is checked on load. A compiled technique is found by a 64-bit key:fold32(FNV-1a-64(template name)) << 32 | permutation, where the permutation is FNV-1a-32 over the vertex factory and its Discarded/PreSkinned/Dismembered flags, the technique index, the render-stage name and the pass index. The recipe reproduces all 19,647 records. - The name is the template's
nameCName, not its file. A copy ofmesh_that keepsdecal.mt name = mesh_reachesdecal mesh_'s programs; a copy with a new name finds none.decal - Programs are per template. Each of the 19,037 programs belongs to exactly one template name, even when bytes are identical elsewhere. A record names a vertex program and an optional pixel program by GUID; each program names the engine modifier slots it reads (its parameter set).
- All programs are
vs_/6_ 0 ps_, signed, with no embedded root signature.6_ 0
8.2 From technique to pipeline state source
- A draw binds a material for a pass; the render template keeps its own technique map and compiles on a miss (key lookup, then the pixel and vertex programs).
- Each program becomes a GpuApi shader, deduplicated by an FNV-1a-32 hash of its bytecode. The bytecode is referenced, not copied.
- The command list collects the shaders and the pass's states into a
D3D12_. At draw time it hashes the state fields (not the bytecode), seeded by the shaders' IDs, and resolves a PSO from an 8,192-entry cache.GRAPHICS_ PIPELINE_ STATE_ DESC - A missing PSO is loaded from an
ID3D12PipelineLibraryby a name derived from the shader hashes, else created withID3D12Device::CreateGraphicsPipelineState, synchronously or as aCompilePSOAsyncjob. - One global graphics root signature, built at start-up, serves every material draw; bindless textures sit in
t0, space1.
8.3 What this means for custom shaders
- The cleanest detour is the cache reader's two lookups (find technique, get program). A copied template with its own name is recognised by its key; the plugin answers with the original's record and its own pixel program under its own GUID, and everything downstream (shader, PSO, pipeline library) separates by itself. Vanilla users of the same template never see it [source for the path; the design is a proposal].
- A replacement pixel program must match the original's input and output signatures, stay within the global root signature's bindings, read material constants from
cb4at the template's registers, reuse the original's parameter set, and be signed SM 6.0 DXIL. - Shipping shaders natively is not possible additively: there is one cache file and no mod path. A plugin-read side cache in the same format is the practical form of "a package ships compiled shaders".
- Every function on the path has an address-library ID, so hooks need no pattern scanning, as with ArchiveXL; object offsets remain version-bound and must be gated.
In-game test asks
Batch these into one prepared session with fixed camera, FOV and light, and record game and framework versions.
- Finish board (first photo-mode session held 25 September). The finish board packaged asks 1–3 as six selector presets through the production pipeline, with its own test card: flat finishes and single-lobe Glossy (Board 1), faceted Shimmer and a coarse glitter proxy (Board 2), and the Fresnel colour shift with its strength-0 control (Boards 3 and 4).
- Capture a camera orbit under fixed light, then a light sweep under a fixed camera, at close and face framing, with a blink.
- The
eye_gloss shell (Glossy route 2) is not on the board; it needs a second component.shadow
- Sqrt-space blend check. Board 5: black Matte patches at 25/50/75 % coverage under the eyes, contrast 0, captured in photo mode with fixed exposure.
- Compare measured luminance with linear and sqrt-space predictions.
- Metal threshold edge. Board 6: a metalness ramp 0 → 0.3 and five steps (0.05–0.3) over Satin.
- Look for a visible seam at 0.1.
- Plate depth and gloss (partly run). Experiment 017 packages the depth comparison (0, 0.1, 0.2 and 0.4 mm lifts), the gloss controls (surface off, roughness forced to 1, roughness +0.12) and a stronger Shimmer, with its own test card. Session 2 (26 September) settled the depth ask: at an extreme close-up 0 mm breaks up while 0.1 and 0.4 mm stay clean, so 0.4 mm stays the default runtime (experiment 020 results). Under a controlled photo-mode light (session 4, 28 September) runtime: Gloss C (roughness forced to 1) is clearly the flattest, so the written roughness is what shows. A, B and D look wet, A the most, and their stripes don't separate at face framing. Shimmer · strong reads as a regular grid of dots far too large ("at the scale you'd see under a microscope"), so it needs randomised, much finer facets or a sheen-first design; the Metal ramp's stripes are its own test pattern (experiment 029 §3.2). It replaced an earlier backlit-translucency ask for the eyelids, which stays unnecessary: the translucency term needs thin geometry, which eyelids over the eyeball are not.
Back-lit ear.Answered in session 4 runtime: translucency runs. A photo-mode light behind and beside the head makes the whole ear glow red-orange, redder than the directly lit neck (ear R/G 1.42 against 1.04), and the no-light frames are neutral. This was with Ultra+'s Character Subsurface Translucency toggle on, so that toggle is a dependency. The light was a local photo-mode light at midnight, while the decoded translucency setup has only a sun term, so local lights reach a transmission path too [hypothesis for which] (skin reference §6.4, experiment 029 §4.6).- Debug views. If a debug-view toggle is found (open question 12), capture Albedo, Roughness, Metalness, Translucency and MaterialID views of the plate once.
Related: Glitter in game · mesh-decal contract · glossy feasibility · colour-shift feasibility · multilayered assessment · multilayered evidence · glint feasibility · finish taxonomy · skin trace · eye/lip optics · backlog. Community sources are acknowledged in the community credits.