Mod Authors - hakasapl/PGPatcher GitHub Wiki
This page will describe best practices for mod and modlist authors packaging their mods/lists to work nicely with PGPatcher.
Always use standard naming conventions for your textures. The following table shows standard conventions for different texture types:
| Texture Type | Suffix |
|---|---|
| Diffuse |
_d.dds or .dds
|
| Normal | _n.dds |
| Model Space Normal | _msn.dds |
| Glow | _g.dds |
| Skin Tint | _sk.dds |
| Height | _p.dds |
| Environment / Cubemap | _e.dds |
| Environment Mask / Complex Material |
_m.dds, _em.dds, _envmask.dds
|
| RMAOS | _rmaos.dds |
| Fuzz | _f.dds |
| Inner Layer | _i.dds |
| Subsurface Tint | _s.dds |
| Coat Normal Roughness | _cnr.dds |
| Backlight |
_b.dds, _bl.dds
|
| Hair Flow Map | _flow.dds |
IMPORTANT If you modify the UV on a mesh to work with your texture specifically, YOU SHOULD PUT YOUR TEXTURE IN A UNIQUE PATH! PGPatcher nor anything else has no way of determining what goes with what so if you do this it is foolproof. This is an issue for a vanilla game too because the user may overwrite your texture with something else that is incompatible with a mesh with a changed UV.
The PGPatcher compatible variant of your mod should not contain:
- Any meshes except those that are custom made for a specific texture (for geometry and UV mapping, not for shader type)
- Including meshes that could otherwise be patched can prevent users from using the meshes they want.
- Any plugins that modify
TXSTorMODLrecords- Unless it is necessary for landscapes or decals, which PGPatcher does not patch
The mod author could include an optional file on their page that includes the above items if the mod author would like to support non-PGPatcher users as well. It is better and cleaner for the users to keep these files separate so PGPatcher users do not have to download the extra file.
If you ship a mesh with your mod you have the option to tell PG NOT to patch a shape in that mesh for a specific material. This should only be done if that particular shape should never be patched even if a different mod supplies different textures for it. PLEASE ONLY USE THIS SPARINGLY WHERE REQUIRED! Don't ruin other people's modlists because you tell PG to ignore everything. To do this you need to add a NiBooleanExtraData block to either the shape or the BSLightingShaderProperty named PG_IGNORE with the boolean data being set to 1 (true). If these conditions are met PG will ignore this shape. See nifskope screenshot below.
In plugins, if any winning record has the record flag 24, which is an otherwise unused flag by the game, PGPatcher won't touch that record, and it will also not patch the mesh attached to that record. HOWEVER, if the same mesh is used for multiple records, PGPatcher will still patch the base mesh if not all records have flag 24, but it will generate a duplicate of it on a new path so the ignored records and meshes remain completely untouched. This should be particularly useful for modlist authors.
This section describes instructions for specific materials.
Parallax doesn't need anything special, just make height maps and follow correct naming conventions for them.
At various points of this wiki I refer to "best practice values". These are outlined here. For those asking where these values came from, it was a group of several complex material mod authors and PGPatcher authors that came up with them. It is critical to have a standard, therefore we have set one. If you choose not to follow it, please include a metadata file (below) to tell PGPatcher what your values are, OR know that your users are going to complain when PGPatcher breaks your textures.
- Follow standard naming conventions (
_m.dds) preferred - PG will apply a dynamic cubemap on anything CM, keep that in mind while developing your mod
- PG will set the environment map scale to
1.0for every mesh patched with complex material. Adjust your texture accordingly. - PG will set the specular strength to
1.0for every mesh patched with complex material. Adjust your texture accordingly. - PG will set specular color to white IF you have metalness (blue channel) in your texture
Should you choose to do so, you can include a JSON file alongside your environment mask file named the same and in the same folder. For example if your file is textures/folderA/texture_m.dds, the JSON would be textures/folderA/texture_m.json. The file supports the following schema:
You do not need all of the fields. Any you include will act as overrides. When not specified, the same defaults as always are applied for these properties.
If you are including prepatched meshes or alternate texture records in plugins for your PBR mod, please ensure the following:
- First of all, try not to if at all possible.
- PBR textures are in the
pbrsubfolder (textures/pbr/whatever) - IF your textures are replacing vanilla textures, ensure that the path of your new PBR diffuse and normal are IDENTICAL to the vanilla variants EXCEPT for the
pbrfolder at the beginning of the path. - You have a pbrnifpatcher json that will match to your prepatched texture set (whether in NIF or plugin) if
pbrfolder is removed from the diffuse/normal slots. PG will remove this part and then check if a json exists that matches it.
- PBR texture swap JSONs should not be included in the main file if a corresponding patcher JSON exists.
- ALL PBR textures must be prefixed with
textures/pbrin their path. - DO NOT include ANY prepatched TXST records in your plugins. PG does this for you and expects existing TXST records to be non-PBR. You can still use TXST records, just don't prepatch them with PBR textures.
Because PBR has many parameters, PG cannot patch for PBR from texture information only. This is why JSON files can be created to tell PG how to patch something for PBR.
You should create a JSON file named whatever you want in the PBRNIFPatcher folder. The file should be a list of JSON objects. An example is below.
[
{
"texture": "fern01", "emissive": false, "parallax": false, "subsurface_foliage":false, "subsurface": false,
"specular_level" : 0.04, "subsurface_color": [1,1,1], "roughness_scale" : 1, "subsurface_opacity" : 1, "displacement_scale" : 1
},
{
"texture": "fern02", "emissive": false, "parallax": false, "subsurface_foliage":false, "subsurface": false,
"specular_level" : 0.04, "subsurface_color": [1,1,1], "roughness_scale" : 1, "subsurface_opacity" : 1, "displacement_scale" : 1
},
{
"texture": "mushroom01", "emissive": false, "parallax": false, "subsurface_foliage":false, "subsurface": false,
"specular_level" : 0.04, "subsurface_color": [1,1,1], "roughness_scale" : 1, "subsurface_opacity" : 1, "displacement_scale" : 1
}
]You can also define defaults which will be applied to every entry unless also defined in the entry like so:
{
"default": {
"vertex_color_lum_mult": 1.5
},
"entries": [
{
"texture": "fern01", "emissive": false, "parallax": false, "subsurface_foliage":false, "subsurface": false,
"specular_level" : 0.04, "subsurface_color": [1,1,1], "roughness_scale" : 1, "subsurface_opacity" : 1, "displacement_scale" : 1
},
{
"texture": "fern02", "emissive": false, "parallax": false, "subsurface_foliage":false, "subsurface": false,
"specular_level" : 0.04, "subsurface_color": [1,1,1], "roughness_scale" : 1, "subsurface_opacity" : 1, "displacement_scale" : 1
},
{
"texture": "mushroom01", "emissive": false, "parallax": false, "subsurface_foliage":false, "subsurface": false,
"specular_level" : 0.04, "subsurface_color": [1,1,1], "roughness_scale" : 1, "subsurface_opacity" : 1, "displacement_scale" : 1
}
]
}NOTE: PG will NOT patch a shape if any texture set from the result of your combined JSON objects in a given match does not exist.
The following fields are available for each JSON object:
Matching fields are used to match a given JSON object to an existing shape. If more than one rule matches, they will be executed sequentially in the order they are in the JSON file. PG will NOT allow matches across JSON files, only one JSON file can match a given shape.
"texture": "" or "match_diffuse": ""
Match an existing diffuse. It will match any diffuse that ends with what you specify in this field. Partial file names are not allowed, it must be at least a full file, or a path, where each component is a full filename.
"match_normal": ""
Same rules as above but match normal instead of diffuse.
"path_contains": ""
This will match any diffuse that contains the string specified in this field anywhere in the diffuse path. Avoid using this when possible, it is a lot slower than match_diffuse and match_normal
"nif_filter": ""
If this field is specified, only NIFs that contain this string in their path will be patched. Avoid using this when possible, it can be slow
"delete": true/false
If delete: true is specified, the matching shape will be deleted from the result mesh.
"smooth_angle": 60
Smooths the normals (and removes doubled vertices) where the angle is less extreme (flatter) than the given number in degrees, useful when sharp edges look bad with high resolution textures. Use this sparingly only when required, it is very costly and will slow down mesh patching
"vertex_colors": true/false
Enable or disable vertex colors, useful if the mesh used vertex colors to change the colors of the old textures.
"vertex_color_lum_mult": 0.0
First convert RGB of vertex color to HSV, then apply the formula 1-(1-ORIGINAL_L)*vertex_color_lum_mult. Used to reduce vertex darkening. Setting this to 0.0 will remove vertex darkening completely. Setting it to 0.5 will reduce the darkening in all vertices as per the formular.
"vertex_color_sat_mult": 0.0
First convert RGB of vertex color to HSV, then apply the formula ORIGINAL_S * vertex_color_sat_mult. Result is clamped between 0.0 and 1.0.
"zbuffer_write": true/false
Apples the zbuffer_write shader flag if true
"specular_level": 0.0
Set the specular level in the shader.
"roughness_scale": 0.0
Set the roughness scale in the shader.
"auto_uv": true/false
Experimental, scales the uvs to keep the pixel density constant on average
"uv_scale": 0.0
Set the UV scale for the shader (both x and y)
By default the patcher will add textures to the set based on parameters set in the JSON. If you do not want the patcher to modify a given slot, you can use lock fields:
"lock_diffuse": true/false
"lock_normal": true/false
"lock_emissive": true/false
"lock_parallax": true/false
"lock_cubemap": true/false
"lock_rmaos": true/false
"lock_cnr": true/false
"lock_subsurface": true/false
In addition, the mod author can explicitly specify a given slot using slot commands (note that the full path must be specified for slots: textures\\PBR\\bla.dds for example):
"slot1": ""
"slot2": ""
"slot3": ""
"slot4": ""
"slot5": ""
"slot6": ""
"slot7": ""
"slot8": ""
"rename": ""
Rename can be used to rename the matching part (from match_diffuse or match_normal) of the JSON entry with the defined rename string. This will apply to all textures while preserving correct suffixes (except if lock_X is specified for any slot).
"emissive": true/false
Enabling this will enable glow and add <prefix>_g.dds to slot 3.
"emissive_scale": 0.0
Set the emissive scale in the shader.
"emissive_color": [0, 0, 0, 0]
Set the emissive color in the shader.
"parallax": true/false
Enabling this will enable parallax and add <prefix>_p.dds to slot 4.
"displacement_scale": 0.0
Set the displacement scale in the shader.
"subsurface": true/false
Enabling this will enable subsurface and add <prefix>_s.dds to slot 8
"subsurface_color": [0, 0, 0]
Set the subsurface color in the shader.
"subsurface_opacity": 0.0
Set the subsurface opacity in the shader.
"coat_normal": true/false
Enabling this will enable multilayer PBR and add <prefix>_cnr.dds to slot 7.
"coat_strength": 0.0
Set the coat strength
"coat_roughness": 0.0
Set the coat roughness
"coat_specular_level": 0.0
Set the coat specular level
"coat_diffuse": true/false
Enabling this will add <prefix>_s.dds to slot 8
"coat_parallax": true/false
Enables parallax for inner layer
To enable fuzz add this:
"fuzz": {
}Then, the following parameters are valid if used inside the fuzz JSON object.
"texture": true/false
If true, <prefix>_f.dds will be added to slot 7.
"color": [ 1, 1, 1 ]
Set fuzz color (if texture is true this is a multiplier)
"weight": 1.0
Set fuzz weight (if texture is true this is a multiplier)
"hair": true/false
Enabling this will enable the PBR hair shader.
To enable glint add this:
"glint": {
}Then, the following parameters are valid if used inside the glint JSON object.
"screen_space_scale": 0.0
Set screen space scale for glint
"log_microfacet_density": 0.0
Set log microfacet density for glint
"microfacet_roughness": 0.0
Set microfacet roughness for glint
"density_randomization": 0.0
Set density randomization for glint
{ "specular_enabled": true, "specular_color": [ 1.0, 1.0, 1.0 ], "specular_strength": 1.0, "glossiness": 80, "environment_map_scale": 1.0, "dynamic_cubemap": true }