Now, CM got a feature allowing to quickly create new skins. It’s still WIP, more types of customization might be added later.
What’s the use of it?
First of all, if you’re making your own mod cars, you might want drivers to be able to quickly create their own skins, so they could select colors, patterns, numbers and other options. Now, it’s possible.
Also, we’re working on adding support to other cars as well, Kunos cars, for example. You can join here or create your own repository and send a link to it to me, so I can include it to CM’s rules sources.
I believe, the easiest way to learn something is by example, so, please, go here and download the whole repository, and then, put it all to “Data (User)”. This way, you’ll be able to see how those rules are written and how can you modify them. This post, on the other hand, is more like a very detailed manual describing all options (it turned out quite a lot of them are needed to allow skin various cars properly).
Automatic detection
By default, CM tries to detect editable textures automatically by textures names and shaders used. Specifically, like this (case matters):
- “Metal_detail.dds”, “carpaint_detail.dds”, “metal_detail.dds”, “car_paint.dds”, “carpaint.dds” — car paint color;
- “car_paint_rims.dds”, “metal_detail_rim.dds”, “Metal_detail_rim.dds” — rims color;
- “caliper_colour.dds”, “metal_detail_caliper.dds”, “Metal_detail_caliper.dds” — caliper color;
- “car_paint_roll_cage.dds” — roll cage color;
- “ext_glass.dds” — color of outside windows;
- “Plate_D.dds” and “Plate_NM.dds” — European number plates.
And txMaps for car paint is being taken from a first material with “ksPerPixelMultiMap_damage_dirt” shader. But you might want to specify more different textures or just replace auto-detected ones with something else.
Specifying your own rules
First of all, where CM takes rules from? At first, it looks for file called “cm_paintshop.json” in car’s “ui” folder, expecting to find rules there. If nothing found, CM checks “Paint Shop” directories in both “AppData\Local\AcTools Content Manager\Data” and “AppData\Local\AcTools Content Manager\Data (User)” (as usual, try not to change “Data” contents since it’s going to be overwritten next time data is updated). And, if nothing else found, CM checks online database for rules.
So, if you’re making a mod car, the best way to specify rules would be to include them in a “cm_paintshop.json” file. But, for editing, it’s better to start with “Data (User)” folder.
Rules format
As you can see, rules are specified in JSON-files. Not a basic JSON though, but JSON with comments, so you might want to switch your Notepad++/Sublime Text/any other text editor to syntax highlight to JavaScript mode to make it look better.
Each JSON-file is an object (check out that Wikipedia article) where keys are cars’ IDs and values are arrays of skin options.
Some rules might reference some additional texture files, for example, for a texture replacement or a custom font. CM will look for those files in a folder or a ZIP-archive next to JSON-file, with the same name (but without “.json” or with “.zip” instead of “.json” for ZIP-archive).
Skin options
Skin option might be either a string or an object. If it’s a string…
"@guess"
: try to guess skin options according to the scheme above;
- anything else: will be considered to be a car ID, from which skin options will be inherited.
And, if it’s an object, the main property it should have is type
, specifying the type of the option. If omitted, CM will assume it’s a basic color
option.
Common skin options parameters:
- enabled: enabled or disabled from a start? by default, only car paint and license plate are enabled;
- name: display name, used for sorting.
Skin option types
Color (color
)
Use it to either replace a texture with a solid-color image, or with a tinted version of another texture (either from the car’s KN5 or shipped with JSON-file with rules).
Parameters:
- texture: name of color texture, required if pairs missing;
- tintBase: tint texture (set to true to use texture or use texture reference) instead of using solid color;
- pairs: tint several textures at once, key-value dictionary, texture name → replacement reference;
- defaultColor: color selected by default, default value is
#ffffff
(white);
- defaultColors: list of colors selected by default (several colors are used with pairs and mask, first color is active with red channel, second color with green and third with blue).
Examples:
{
"type": "color",
"name": "Leather",
"texture": "int_leather_color.dds",
"defaultColor": "#a52a2a"
}
- Colorized calipers (original texture is of gray color, so it’s also auto-leveled):
{
"type": "color",
"name": "Calipers",
"texture": "calipper.dds",
"autoLevel": true,
"defaultColor": "#181818"
}
- Another sort of colorized calipers (here, original texture to be colorized is taken from rules resources, colorized areas are limited by mask):
{
"type": "color",
"name": "Calipers",
"pairs": {
"EXT_Calipers.dds": {
"source": "./ks_alfa_mito_qv/calipers_ao.png",
"mask": "./ks_alfa_mito_qv/calipers_mask.png"
}
},
"defaultColors": [ "#c90b0b" ],
}
{
"type": "color",
"name": "Rims",
"pairs": {
"1M_Rim_Color.DDS": {
"source": "./bmw_1m/rim_base.png",
"mask": "./bmw_1m/rim_mask.png"
},
"1M_Rim_Blur_Color.dds": {
"source": "./bmw_1m/rim_blur_base.png",
"mask": "./bmw_1m/rim_mask.png"
}
},
"defaultColors": [ "#f7f7f7" ]
}
Tinted windows (tintedWindow
)
Extended version of Color (color
), inheriting all parameters. In case you want to make window colors customizable.
Parameters:
- All parameters from Color (
color
);
- defaultOpacity: opacity selected by default, default value is
0.23
;
- fixedColor: set it to
true
to stop user from changing color (defaultColor
will be used), default value is false
.
Examples:
{
"type": "tintedWindow",
"texture": "ext_glass.dds",
"defaultOpacity": 0.23,
"fixedColor": false
}
Replace by transparent (transparentIfFlagged
)
If enabled, replaces a texture with a transparent piece.
Parameters:
- texture: name of color texture, required if textures missing;
- textures: several names of textures, if needed;
- inverse: inverse behavior (replace when not active).
Examples:
{
"type":
"transparentIfFlagged",
"name": "Yellow headlights",
"texture": "ext_headlight_yellow.dds",
"inverse": true /* headlights are yellow when texture is non-transparent*/,
"enabled": true
}
Replace by solid color (solidColorIfFlagged
)
Same as Replace by transparent (transparentIfFlagged
), but replaces with a solid color texture.
Parameters:
- All parameters from Replace by transparent (
transparentIfFlagged
);
- color: color of texture, default value is
#ffffff
(white);
- opacity: opacity of texture, default value is
1.0
(opaque);
Replace by another texture (replacedIfFlagged
)
If enabled, replaces one or several textures by textures either from KN5 or from resources next to JSON-file.
Parameters:
- inverse: inverse behavior (replace when not active);
- pairs: key-value dictionary, texture name — replacement reference.
Examples:
{
"type": "replacedIfFlagged",
"name": "Black exhaust",
"pairs": {
"exhaust.dds": "./acc_nissan_r33_drift__exhaust.dds",
"exhaust_map.dds": "./acc_nissan_r33_drift__exhaust_map.dds"
}
}
Car paint (carPaint
)
As you might imagine, this one is quite complicated. Allows to adjust txDetails
(background color or pattern), txDiffuse
(actual livery: stripes and that) and txMaps
(material parameters, such as shininess or roughness).
txDetails parameters:
- texture: name of
txDetails
texture;
- defaultColor: color selected by default, default value is
#ffffff
(white);
- colorAvailable: is color can be changed, default value is
true
;
- flakesAvailable: are metallic flakes can be used for this car, default value is
true
;
- flakesSize: texture size for flakes, default value is
512
;
- candidates: optional object allowing to replace
txDetails
with a different texture, keys are options’ names and values are replacement sources (optionally, you can set colored to true for those sources to allow them being colored).
txMaps parameters:
- mapsTexture: name of
txMaps
texture (optional);
- mapsAutoLevel: auto-level current txMaps texture before modifying, helps if built-in one is dimmed;
- mapsDesaturate: desaturate current txMaps texture before modifying, helps if built-in one is colored;
- mapsDefaultTexture: use different texture from KN5 or folder or ZIP as txMaps.
txDiffuse parameters:
- patternTexture: name of
txDiffuse
texture (optional);
- patternBase: reference to the base AO texture (alpha-channel is not required);
As a reminder: CM can create its own textures, use that feature if you can’t find AO anywhere.
- patternOverlay: reference to texture which will be put on top of AO+pattern (for example, with badges), optional;
- patternSize: defines the size of
txDiffuse
textures generated, might be overridden per pattern;
- patterns: list of patterns, each contains name, number of colors, reference to pattern and, if needed, reference to custom overlay.
Pattern parameters:
- name: name of the pattern;
- pattern: reference to a pattern texture (red channel for first color, green for second and blue for third), alpha channel specifies where txDetails will be used instead;
- defaultColors: colors by default (from one up to three); if missing, pattern will be considered non-colorizable;
- overlay: overrides patternOverlay for current pattern;
- size: overrides patternSize for current pattern;
- numbers: list of numbers for pattern.
Number parameters:
- size: font size, in pixels;
- font: font name or TTF resource reference (you might want to use a tool like this to remove all non-digits chars to save weight);
- left: label X coordinate, in pixels;
- top: label Y coordinate, in pixels;
- angle: angle, in degress;
- horizontalAlignment: either
left
, center
or right
;
- verticalAlignment: either
top
, center
or bottom
;
- color: either fixed color value or a number referencing a color from pattern (from 0);
- weight: font weight:
light
, normal
, bold
, … (could be a number, 100…950);
- style: font style:
normal
, italic
or oblique
;
- stretch: font stretch:
condensed
, normal
, expanded
, … (could be a number, 1…9).
Examples:
- Basic car paint with txMaps taken from KN5:
{
"type": "carPaint",
"texture": "car_paint.dds",
"mapsTexture": "carpaint_MAP.dds",
"mapsAutoLevel": true,
"defaultColor": "#deb887"
}
{
"type": "carPaint",
/* color (txDetails) */
"texture": "tn_car_paint.dds",
"colorAvailable": true, /* set to false to allow replacements (candidates) only */
"flakesSize": 512,
"flakesAvailable": true, /* set to false to disable flakes */
"defaultColor": "#deb887",
"candidates": { /* optional replacements for txDetails */
"Carbon": "./carbon_detail.dds",
"Carbon (Colored)": { "path": "./carbon_detail.dds", "colored": true },
},
/* maps (txMaps) */
"mapsTexture": "tn_carpaint_MAP.dds",
"mapsDefaultTexture": "tn_carpaint_SKIN.dds" /* instead of auto-leveling */,
/* pattern (txDiffuse) */
"patternTexture": "tn_carpaint_SKIN.dds",
"patternBase": "tn_carpaint_SKIN.dds",
"patterns": [
{
"name": "TN Stripe",
"defaultColors": [ "#ffffff" ],
"pattern": "./acc_peugeot_504_tn__stripe.png",
"overlay": null
},
{
"name": "TN Stripe+Numbers",
"defaultColors": [ "#ffffff" ],
"pattern": "./acc_peugeot_504_tn__stripe.png",
"overlay": null,
"numbers": [
{ "size": 220, "font": "./lobster-digits.ttf", "left": 820, "top": 420, "angle": 180,
"horizontalAlignment": "center", "verticalAlignment": "center", "color": 0,
"weight": "bold" },
{ "size": 160, "font": "./lobster-digits.ttf", "left": 820, "top": 1840, "angle": 0,
"horizontalAlignment": "center", "verticalAlignment": "center", "color": 0,
"weight": "bold" },
]
},
{
"name": "Numbers",
"defaultColors": [ "#ffffff" ],
/* wonder why pattern is a color instead of a texture reference?
scroll down to “Sources” */
"pattern": "#00000000",
"size": { "width": 2048, "height": 2048 },
"overlay": null,
"numbers": [
{ "size": 220, "font": "./lobster-digits.ttf", "left": 820, "top": 420, "angle": 180,
"horizontalAlignment": "center", "verticalAlignment": "center", "color": 0,
"weight": "bold" },
{ "size": 160, "font": "./lobster-digits.ttf", "left": 820, "top": 1840, "angle": 0,
"horizontalAlignment": "center", "verticalAlignment": "center", "color": 0,
"weight": "bold" },
]
},
{
"name": "Gradient",
"defaultColors": [ "#ffffff", "#ff0000" ],
"pattern": "./acc_peugeot_504_tn__gradient.png",
"overlay": null
},
],
}
Screenshot:
With two channels, it’s possible to implement a smooth gradient as well.
Pattern (pattern
)
Use it if you need pattern functionality from Car paint (carPaint
) without any txDetails
and txMaps
stuff.
Parameters:
- texture: name of
txDiffuse
texture (optional);
- base: reference to the base AO texture (alpha-channel is not required);
- overlay: reference to texture which will be put on top of AO+pattern (for example, with badges), optional;
- size: defines the size of
txDiffuse
textures generated, might be overridden per pattern;
- patterns: list of patterns, each contains name, number of colors, reference to pattern and, if needed, reference to custom overlay.
Examples:
- Numbers on seats (purely as an example):
{
"type": "pattern",
"name": "Seats Number",
"texture": "tn_int_leather.dds",
"patterns": [
{
"name": "Numbers",
"defaultColors": [ "#ffffff" ],
"pattern": "#00000000",
"size": { "width": 2048, "height": 2048 },
"overlay": null,
"numbers": [
{ "size": 220, "font": "./lobster-digits.ttf", "left": 420, "top": 1840, "angle": 0,
"horizontalAlignment": "center", "verticalAlignment": "center", "color": 0, "weight": "bold" },
{ "size": 160, "font": "./lobster-digits.ttf", "left": 820, "top": 1840, "angle": 0,
"horizontalAlignment": "center", "verticalAlignment": "center", "color": 0, "weight": "bold" },
]
}
]
}
License plates (licensePlate
)
License plate, with styles taken from “Data\License Plates”:
Parameters:
- style: name of preferred style, default value is
europe
;
- texture: name of diffuse texture, default value is
Plate_D.dds
;
- normals: name of normals texture, default value is
Plate_NM.dds
.
Examples:
{
"type": "licensePlate",
"style": "Europe",
"texture": "Plate_D.dds",
"normals": "Plate_NM.dds"
}
Screenshot:
Sources
Here and there, you might need to reference other textures — either from original KN5 file, from JSON-file resources (a ZIP-file or a folder with the same name next to JSON-file as mentioned above), or something else. Here is how it works:
- Put texture name as it is, like so:
"metal_detail.dds"
, and CM is going to look for it in KN5 file;
- Add “.\” or “./” before its name, like so:
"./texture_name.dds"
, to specify that texture should be taken from JSON-file resources;
- Or you can use a hex color instead:
"#ff00ff"
(just make sure it’s starting with “#”);
- And, if you want to use the KN5 texture with the same name as output, use
"@self"
.
Texture preparations
Also, instead of a string, you can use an object with extra properties specifying how input texture should be prepared before. In this case, just put a texture name as "path"
. So, if you want to use "texture_name.dds"
, but desaturated: { "path": "texture_name.dds", "desaturate": true }
.
Parameters:
- autoLevel: set to true to enable auto-leveling (some sort of Photoshop’s Auto Contrast analog);
- desaturate: set to true to desaturate texture before using.
Channels shuffling
Just in case, CM also allows to use only particular channels from input texture or swap them. To do so, simply put channels after texture name, like so: "texture_name.dds:a"
.
Examples:
"texture_name.dds:a"
: take only alpha-channel of provided texture;
"texture_name.dds:rgba"
: use texture as it is;
"texture_name.dds:rbga"
: swap green and blue channels;
"texture_name.dds:raaa"
: keep red channel, but replace rest with alpha;
"texture_name.dds:ra"
: same (in case there are less than four letters, last one will be repeated);
"texture_name.dds:rgb0"
: use colors, but replace alpha-channel with zeros (making it completely transparent);
"texture_name.dds:rgb1"
: same, but making it opaque.
And, speaking of objects, apart from specifying preparation parameters, you can map channels from various textures as well, like so:
{ "red": "ExtMisc.dds:a", "blue": "./dallara_fx17/maps_mask.png:r", "alpha": "#88ffffff" }
Destinations
Another small piece is how result textures are saved. By default, CM uses RGBA8888 format for all small and DTX5 for all large textures to avoid losing potentially important alpha-channel, apart from txMaps textures (for which, alpha-channel is not needed). But you can set a specific format to be used while saving, by simply adding a prefix to result textures’ names.
CM uses NVIDIA Texture Tools library to encode textures, so it should be all right. Thanks to JusTiCe8 for the tip, by the way.
Formats:
"texture_name.dds:dxt1"
: DXT1 (4 bits per pixel without alpha-channel, lossy);
"texture_name.dds:dxt5"
: DXT5 (8 bits per pixel with alpha, lossy);
"texture_name.dds:l"
: luminance only (8 bpp, perfect for grayscale textures without alpha);
"texture_name.dds:la"
: luminance and alpha (16 bpp, good for AO maps with alpha if you want to get rid of compression artifacts);
"texture_name.dds:rgb565"
: RGB 5.6.5 (16 bpp without alpha);
"texture_name.dds:rgba4444"
: Only 4 bits per color (16 bpp, with alpha);
"texture_name.dds:rgba"
: no compression (32 bpp with alpha);
"texture_name.dds:rgb"
: no compression (24 bpp without alpha).
Examples:
{
"type": "color",
"name": "Leather",
"texture": "int_leather_color.dds:dxt1",
"defaultColor": "#a52a2a"
}
- 4 bits per channel would work fine:
{
"type": "transparentIfFlagged",
"name": "Yellow headlights",
"texture": "ext_headlight_yellow.dds:rgba4444",
"inverse": true /* headlights are yellow when texture is non-transparent*/,
"enabled": true
}