Overview
A Material Target declares which material to modify and exactly what to do to it when its parent Skin Group is active on a gear. Each target lives in its own .mattarget.json file placed anywhere inside the skin group’s folder tree — the mod discovers them recursively.
For a easy way to create Material Target manifest files, check out Editing Material Targets.
Warning
Multiple Material Targets with different configurations that target the same material within the same Skin Group is undefined behavior! There is no guarantee as to which material target definition will be used. If you want to provide different versions of a gear part (say for different guns), you NEED to do so in different Skin Groups!
File Naming & Folder Structure
Files must have the extension .mattarget.json. The filename itself is free-form.
my-skin/
manifest.skingroup.json
rifle.mattarget.json ← any name is fine
details/
scope.mattarget.json ← nesting is fine too
Manifest Schema
{
"material_name": "Front_Pistol_4",
"match_groups": [ /* optional variant filter */ ], // legacy: matchGroups
"shader": "Cell/Player/CustomGearShader", // optional shader override
"properties": {
"_MainTex": {
"type": "Texture2D",
"data": { "src": "textures/albedo.png" }
}
}
}Fields
| Field | Type | Required | Description |
|---|---|---|---|
material_name | string | ✓ | Exact name of the material to match. Must match the in-game material name precisely (case-sensitive). |
match_groups | array of match group objects | — | Optional variant filter used to disambiguate materials that share a name. See Variant Matching. When absent or empty, all variants of the named material are matched. |
shader | string | — | If set, the material’s shader is replaced with this shader before any properties are applied. |
properties | object (property map) | — | Dictionary of shader property name → property definition. See Properties. |
Variant Matching
Some materials in GTFO share the same name (for example, "Spear" exists on multiple unrelated items). matchGroups lets you add additional texture-name conditions to narrow down the match.
The structure mirrors the filter system on Skin Groups: it is a DNF. The target matches when any group in matchGroups matches, and a group matches when all of its conditions match.
Each condition checks whether a specific texture slot on the material carries an expected in-game texture name:
"matchGroups": [
{
"conditions": [
{ "slot": "_MainTex", "value": "mat_spear_playerMain" }
]
}
]When matchGroups is empty or omitted, the target matches all variants of the material (wildcard).
Condition Object Fields
| Field | Type | Description |
|---|---|---|
slot | string | The shader texture slot to inspect (e.g. _MainTex). |
value | string | The expected in-game texture name currently assigned to that slot. |
Use the Select Material dialog in the SkinGroup Editor, or check the gear dump, to find and fill in the correct in-game texture names.
Properties
The properties map is keyed by shader property name (e.g. _MainTex, _Glossiness). Each value is an object with a type discriminator and a data payload:
"properties": {
"_MainTex": { "type": "Texture2D", "data": { "src": "albedo.png" } },
"_Glossiness": { "type": "Float", "data": { "value": 0.5 } }
}If a property name does not exist on the material’s current shader, or the type does not match, the property is skipped and a warning is logged — it will not cause a crash.
Property Types
Texture2D
Sets a texture slot.
{
"type": "Texture2D",
"data": {
"src": "textures/albedo.png",
"options": "Albedo"
}
}| Field | Type | Required | Description |
|---|---|---|---|
src | string | ✓ | Path to the texture file, relative to the .mattarget.json file’s directory. Can also be a Texture Macro expression (e.g. @WHITE). |
options | string or object | — | Import options. When omitted, options are inferred from the slot name automatically (see below). |
Import Options
| Value | Linear | Mipmaps | Use for |
|---|---|---|---|
"Albedo" | false | true | Color/albedo maps |
"Data" | true | true | Normal maps, metallic-smoothness, masks |
"AlbedoNoMips" | false | false | UI / decal textures that should not be mipmapped |
"DataNoMips" | true | false | Data maps that should not be mipmapped |
You can also supply a custom object (this is the most canonical form):
"options": { "linear": true, "mipmaps": false }When options is omitted the mod infers sensible defaults from the slot name — for example, slots containing normal or bump default to linear + no mipmaps, while color slots default to non-linear + no mipmaps. It is fine to rely on our inference for standard Unity shader slots.
Mipmaps
The base game will not create mipmaps for the custom textures that we load. To include mipmaps, set the mipmaps key to true for import options as mentioned above.
Internally we initialize textures using the provided options by calling the following
new Texture2D(..., mipChain: options.Mipmaps, linear: options.Linear);Special Cases
Emissive Maps
When the property name is _EmissiveMap, the mod automatically enables the ENABLE_EMISSIVE material keyword so the emissive actually renders.
Float
Sets a float or range shader property.
{
"type": "Float",
"data": { "value": 0.75 }
}| Field | Type | Description |
|---|---|---|
value | float | The float value to set. |
Color
Sets a color shader property. Each channel is a float in the 0–1 range.
{
"type": "Color",
"data": { "r": 1.0, "g": 0.2, "b": 0.2, "a": 1.0 }
}| Field | Type | Default | Description |
|---|---|---|---|
r | float | 0 | Red channel (0–1) |
g | float | 0 | Green channel (0–1) |
b | float | 0 | Blue channel (0–1) |
a | float | 1 | Alpha channel (0–1) |
Vector
Sets a Vector4 shader property (commonly used for tiling/offset or custom packed data).
{
"type": "Vector",
"data": { "x": 2.0, "y": 2.0, "z": 0.0, "w": 0.0 }
}| Field | Type | Default | Description |
|---|---|---|---|
x | float | 0 | X component |
y | float | 0 | Y component |
z | float | 0 | Z component |
w | float | 0 | W component |
Full Example
{
"material_name": "Head_Hammer_5",
"matchGroups": [
{
"conditions": [
{ "slot": "_MainTex", "value": "Head_Hammer_5_Albedo" }
]
}
],
"properties": {
"_MainTex": {
"type": "Texture2D",
"data": { "src": "textures/albedo.png", "options": "Albedo" }
},
"_NormalMap": {
"type": "Texture2D",
"data": { "src": "textures/normal.png", "options": "Data" }
},
"_EmissiveMap": {
"type": "Texture2D",
"data": { "src": "textures/em.png" } // options inferred to be "AlbedoNoMips" for _Em
},
"_MetallicGlossMap": {
"type": "Texture2D",
"data": { "src": "@METALLIC_SMOOTHNESS(0.8,0.6)" }
},
"_Glossiness": {
"type": "Float",
"data": { "value": 0.6 }
}
}
}