Mod Authors - hakasapl/PGPatcher GitHub Wiki
This page will describe best practices for mod authors packaging their mods to work nicely with PG.
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
|
The PG 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
TXST
orMODL
records- PG will NOT patch a specific mesh if the user specifies that a non-special-shader mod (not Parallax, CM, or PBR) has higher priority than a special shader mod. This is intended to allow the user to use vanilla mods mixed with special shader mods. If the mod author includes edits to TXST records, it will be left alone and there would be a mismatch between the shader in the mesh and what the actual textures reflect. This is particularly important for PBR.
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-PG users as well. It is better and cleaner for the users to keep these files separate so PG users do not have to download the extra file.
NOTE: Landscape and decal mods are an exception to the above since landscape isn't meshes. I don't think a user would want a different mod running their dirtcliffs than their landscapes so the above rules can be ignored for landscape mods.
This section describes instructions for specific materials.
Parallax doesn't need anything special, just make height maps and follow correct naming conventions for them.
Some guidelines to follow for Complex Material mods:
- 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.0
for every mesh patched with complex material. Adjust your texture accordingly. - PG will set the specular strength to
1.0
for 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
General rules to follow:
- 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/pbr
in their path. While it does work without doing this, PG expects this convention and won't work correctly without it. - 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.
"nif_filter": ""
If this field is specified, only NIFs that contain this string in their path will be patched.
"delete": true/false
If delete: true
is specified, the matching shape will be deleted from the result mesh.
"smooth_angle": true/false
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.
"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
"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, 0.0, 0.0]
Set the UV scale for the shader.
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