CustomShaderLoaderAlt
Improvements over Regguise/CustomShaderLoader v1.72
Improvements over Regguise/CustomShaderLoader v1.72
✦ New Features
1. Material Slot Limit: 10 → 50
The original plugin hardcoded a limit of 10 material slots for Clothing/CUA mode. Any CUA or clothing item with more than 10 materials could not have its extra slots controlled.
The improved version raises the limit to 50 Clothing/CUA slots (skin slots remain at 30), supporting large CUAs and high-material-count clothing items.
2. New Property Type:
vector4The original only supported 3D vectors (
vector = XYZ).The improved version adds
vector4, providing four sliders (X/Y/Z/W) for shader properties that require a Vector4 parameter (e.g. packed tiling+offset, custom parameter groups).
JSON:
{
"name": "_TilingOffset",
"displayName": "Tiling & Offset",
"type": "vector4",
"defaultVector4": { "x": 1.0, "y": 1.0, "z": 0.0, "w": 0.0 },
"minVector4": { "x": 0.1, "y": 0.1, "z": -2.0, "w": -2.0 },
"maxVector4": { "x": 10.0, "y": 10.0, "z": 2.0, "w": 2.0 }
}
3. New Property Type:
label — Section HeadersThe original had no way to group properties visually — everything was stacked without structure.
The improved version introduces the
label type, which inserts a colored banner to visually separate property groups.defaultColor: Banner background color (supports#RRGGBBhex or named colors)textColor: Text color; if omitted, black or white is chosen automatically based on background luminanceheight,fontSize: Control banner dimensions
JSON:
{ "name": "", "displayName": "─── Base Colors ───", "type": "label", "defaultColor": "#1a2a4a", "height": 45, "fontSize": 26 },
{ "name": "", "displayName": "─── Lighting ───", "type": "label", "defaultColor": "#2a1a1a", "textColor": "#ffcc88", "height": 45, "fontSize": 26 }
4. New Property Type:
column — Left/Right Column ToggleThe original placed all shader properties in the right column only (hardcoded
rightSide = true), leaving the left column completely empty.The improved version adds the
column type — inserting it switches all subsequent properties to the other column, enabling a balanced two-column layout.
JSON:
{ "name": "_Color", "displayName": "Base Color", "type": "color", "defaultColor": "white" },
{ "name": "_Emission", "displayName": "Emission", "type": "color", "defaultColor": "black" },
{ "name": "", "displayName": "", "type": "column" },
{ "name": "_Metallic", "displayName": "Metallic", "type": "float", "defaultValue": 0.0, "minValue": 0.0, "maxValue": 1.0 },
{ "name": "_Gloss", "displayName": "Smoothness", "type": "float", "defaultValue": 0.5, "minValue": 0.0, "maxValue": 1.0 }
The two color pickers appear in the right column; after
column, the sliders switch to the left column.5. New Property Type:
tab — Tab-Based LayoutThe original had no tab support — large property lists required endless scrolling.
The improved version integrates CustomTabUI: placing a
tab entry in the JSON creates a tab button at the top of the plugin UI, and all subsequent properties are grouped under that tab.
JSON:
{ "name": "", "displayName": "Basic", "type": "tab", "tabWidth": 100 },
{ "name": "_Color", "displayName": "Base Color", "type": "color", "defaultColor": "white" },
{ "name": "_Metallic", "displayName": "Metallic", "type": "float", "defaultValue": 0.0, "minValue": 0.0, "maxValue": 1.0 },
{ "name": "", "displayName": "Textures", "type": "tab", "tabWidth": 100 },
{ "name": "_MainTex", "displayName": "Albedo", "type": "texture", "wrapMode": "Repeat" },
{ "name": "_BumpMap", "displayName": "Normal Map", "type": "texture", "wrapMode": "Repeat" }
toggle: New keyword Field — Shader Keyword ControlThe original
toggle only set a shader property's float value (0/1), with no ability to control #pragma multi_compile keyword branches.The improved version adds an optional
keyword field — toggling the switch also calls EnableKeyword / DisableKeyword.
JSON:
{ "name": "_UseNormalMap", "displayName": "Enable Normal Map", "type": "toggle", "defaultValueBool": false, "keyword": "USE_NORMAL_MAP" },
{ "name": "_UseEmission", "displayName": "Enable Emission", "type": "toggle", "defaultValueBool": false, "keyword": "EMISSION_ON" }
Corresponding shader code:
Code:
#pragma multi_compile_local _ USE_NORMAL_MAP
#pragma multi_compile_local _ EMISSION_ON
texture: New wrapMode FieldThe original applied the default wrap mode to all textures with no way to override it. The improved version lets you specify wrap mode per texture:
| Value | Behavior |
|---|---|
Repeat (default) | Tile and repeat |
Clamp | |
Mirror | Mirrored tiling |
JSON:
{ "name": "_MainTex", "displayName": "Albedo", "type": "texture", "wrapMode": "Repeat" },
{ "name": "_MaskTex", "displayName": "Mask", "type": "texture", "wrapMode": "Clamp" },
{ "name": "_FlowMap", "displayName": "Flow Map", "type": "texture", "wrapMode": "Mirror" }
✦ Bug Fixes
8. WalkAndGetParentItems: No Longer Overwrites containingAtom
The original accidentally reassigned
containingAtom while walking parent objects:
C#:
containingAtom = parent.GetComponent<Atom>(); // ← overwrites the plugin's own host reference!
In Clothing mode, this replaced
containingAtom with the clothing's host Person Atom, breaking all downstream logic that relied on it.Fix: A local variable
walkedAtom is used for traversal comparison; containingAtom is never modified.9. RestoreShaderPropertiesFromJSON: Person Mode Wait Condition Fixed
Original wait condition:
C#:
yield return new WaitUntil(() => shaderPropertyInitDone && (dazSkinWrap != null || pluginMode.val == "cua"));
In Person mode with no clothing selected,
dazSkinWrap is null and the mode is not "cua", so the coroutine waits forever — skin shader properties never restore.Fix: Added
pluginMode.val == "person" branch:
C#:
yield return new WaitUntil(() => shaderPropertyInitDone && (dazSkinWrap != null || pluginMode.val == "cua" || pluginMode.val == "person"));
10. RestoreFromJSON: Removed Redundant ApplyShaderToMaterials Calls Inside Loop
The original called
ApplyShaderToMaterials() on every loop iteration:
C#:
for (int i = 0; i < slots.Count ...) {
materialSlotStorables[i].valNoCallback = slots[i].AsBool;
ApplyShaderToMaterials(); // ← fires every iteration!
}
10 material slots = 10 redundant calls. Fix: Moved outside the loop — called once after all slots are restored.
11. Vector Properties: Fixed Order-Dependent Accumulation Logic
The original accumulated
xValue/yValue and only submitted the vector upon encountering _Z, relying on Dictionary iteration in X→Y→Z order (not guaranteed):
C#:
if (propertyname.EndsWith("_Z")) {
UpdateShaderProperty(baseName, new Vector3(xValue, yValue, val)); // wrong if order differs
}
Fix: Uses
HashSet<string> processedVectorBases to track processed base names, reads all components at once before submitting, and correctly handles the W component of vector4.12. Texture Callback: Fixed Passing Texture Name Instead of Path
The original passed
tex.name (Unity's internal asset name) instead of the disk path:
C#:
(Texture2D tex) => TexturePropertyCallback(tex.name) // ← can't match a disk path
This caused the texture load callback to fail when trying to update the shader property. Fix: Passes the full file URL and applies complete texture settings (
wrapMode, filterMode, anisoLevel).13. Log Writing: Eliminated Linear I/O Growth
The original read the entire log file before every write:
C#:
string existingContent = FileManagerSecure.ReadAllText(_logFilePath); // reads entire file each time
FileManagerSecure.WriteAllText(_logFilePath, existingContent + message, ...);
Cost grew linearly with file size. Fix: Maintains
_logFileContent in memory and appends directly before writing.14. CUA Material Restore: Added defaultShaders Bounds Check
The original restore loop lacked a length check on
defaultShaders, risking an index-out-of-bounds exception. Fix: Added && i < defaultShaders.Count.✦ Full Configuration Example: Clothing Shader
Demonstrates label grouping / two-column layout / keyword / time animation / vector4
JSON:
[
{ "name": "", "displayName": "─── Colors ───", "type": "label", "defaultColor": "#1a1a2e", "height": 42 },
{ "name": "_Color", "displayName": "Base Color", "type": "color", "defaultColor": "#888888" },
{ "name": "", "displayName": "", "type": "column" },
{ "name": "_Metallic", "displayName": "Metallic", "type": "float", "defaultValue": 0.8, "minValue": 0.0, "maxValue": 1.0 },
{ "name": "_Smoothness", "displayName": "Smoothness", "type": "float", "defaultValue": 0.6, "minValue": 0.0, "maxValue": 1.0 },
{ "name": "", "displayName": "─── Textures ───", "type": "label", "defaultColor": "#1a2e1a", "height": 42 },
{ "name": "_MainTex", "displayName": "Albedo", "type": "texture", "wrapMode": "Repeat" },
{ "name": "_BumpMap", "displayName": "Normal Map", "type": "texture", "wrapMode": "Repeat" },
{ "name": "_UseNormal", "displayName": "Enable Normal", "type": "toggle", "defaultValueBool": true, "keyword": "USE_NORMAL_MAP" },
{ "name": "", "displayName": "─── Dynamic ───", "type": "label", "defaultColor": "#2e1a2e", "height": 42 },
{ "name": "_CustomTime", "displayName": "Time Animation", "type": "time" },
{ "name": "_TilingOffset", "displayName": "Tiling/Offset", "type": "vector4",
"defaultVector4": { "x": 1.0, "y": 1.0, "z": 0.0, "w": 0.0 },
"minVector4": { "x": 0.1, "y": 0.1, "z": -2.0, "w": -2.0 },
"maxVector4": { "x": 10.0, "y": 10.0, "z": 2.0, "w": 2.0 } }
]