No description
  • C# 74.1%
  • Python 25.3%
  • Batchfile 0.6%
Find a file
2026-07-09 22:52:16 -05:00
kkunity_converter Document sidecars in a README table; drop unused KK_LightDarkMaterials.json 2026-07-09 21:12:14 -05:00
kkunity_plugin Add build scripts for converter, plugin, and release; fix PyInstaller multiprocessing and DPI scaling in GUI 2026-07-09 22:52:16 -05:00
.gitignore Add build scripts for converter, plugin, and release; fix PyInstaller multiprocessing and DPI scaling in GUI 2026-07-09 22:52:16 -05:00
build_converter.bat Add build scripts for converter, plugin, and release; fix PyInstaller multiprocessing and DPI scaling in GUI 2026-07-09 22:52:16 -05:00
build_plugin.bat Add build scripts for converter, plugin, and release; fix PyInstaller multiprocessing and DPI scaling in GUI 2026-07-09 22:52:16 -05:00
build_release.bat Add build scripts for converter, plugin, and release; fix PyInstaller multiprocessing and DPI scaling in GUI 2026-07-09 22:52:16 -05:00
convert.py Emit Unity HumanTemplate (.ht) sidecar; rename cf_J_Chin_Base to Jaw 2026-07-09 20:07:46 -05:00
gui.py Add build scripts for converter, plugin, and release; fix PyInstaller multiprocessing and DPI scaling in GUI 2026-07-09 22:52:16 -05:00
README.md Document sidecars in a README table; drop unused KK_LightDarkMaterials.json 2026-07-09 21:12:14 -05:00
requirements.txt update 2026-06-18 15:24:03 -05:00
run_gui.bat Project rename 2026-06-18 13:56:08 -05:00

Koikatsu → Unity Exporter

A two-part pipeline that turns a Koikatsu / Koikatsu Sunshine character into Unity-ready assets:

  1. kkunity_plugin/ — an in-game BepInEx plugin (the exporter). Runs inside KK / KKS, bakes the character's materials and skeleton, and dumps an export folder (model.pmx + baked textures + KK_*.json sidecars + screenshots).
  2. kkunity_converter/ + convert.py / gui.py — a pure-Python converter. Reads that export folder and produces:
    • a skinned, morph-target .glb (geometry + rig + blendshapes), and
    • the loose unity_export folder (per-material textures, JSON sidecars, body masks) that a custom Unity runtime loader reads, optionally packed into a single .kkm archive.

The converter is pure Python — no Blender, no game, no Unity required to run the conversion. Everything (texture compositing, rig prep, morph math, GLB writing) is done with numpy / Pillow / scipy / pygltflib. The plugin is the only part that needs the game.

Koikatsu (game) ──[kkunity_plugin]──▶ export folder ──[kkunity_converter]──▶ .glb / unity_export / .kkm

Part 1 — The exporter plugin (kkunity_plugin/)

A BepInEx plugin (GUID kkunity.plugin) that adds a "kkunity Exporter" panel to the character maker. It bakes each coordinate's materials into flat albedo composites, captures the skeleton and morphs, and writes the export folder the converter consumes.

What it produces

For the selected character it writes Export_PMX/<timestamp>_<name>/ containing:

Outfit 00/
  model.pmx               that coordinate's mesh + skeleton + morphs
  baked materials/        one composited (lit/dark-shaded) albedo PNG per material
  cf_m_body_AM_00.png     per-coordinate body alpha mask
  screenshot.png          front preview (transparent bg, auto-cropped)
  screenshot back.png     back preview
Outfit 01/ ...            one folder per exported coordinate
card_data.png             the character card
KK_*.json                 sidecars (see below)

The base/body pass bakes the shared body mesh neutral so per-outfit pushup morphs (pushup_outfit_NN) can deform it.

Sidecars written (lean mode, the 12 the converter and its Unity runtime loader consume):

Sidecar Contains
KK_MaterialDataComplete.json One record per mesh-renderer material slot: the renderer's path/name, coordinate index, and each material's shader name plus render state (cull / cutoff / stencil / ZWrite / alpha mode). The file materials are reconstructed from.
KK_Coordinates.json Per-outfit manifest: each coordinate's name and the list of worn clothing + accessory item names (only the running game can resolve these).
KK_MaterialData.json Per-material shader property table — declared property names and types (Texture / Color / Float) with their values, including _ST tiling transforms and clothing-state floats.
KK_TextureData.json Per-texture UV settings (wrap mode, offset, tiling scale), keyed by texture filename.
KK_DynamicBoneData.json Per-coordinate dynamic-bone (sway physics) chains: root bone plus its damping / elasticity / stiffness curve settings.
KK_DynamicBoneColliderData.json Per-coordinate colliders the dynamic bones collide against: name, shape (radius / height / direction), center, offset rotation, and scale.
KK_CoordinateBoneModifiers.json Per-outfit ABMX bone changes (position / rotation / scale) that differ from the base coordinate, on the shared skeleton.
KK_EditBoneInfo.json Every bone's local and world transform (TRS + matrix) in the game's bone frame; used to orient the exported skeleton so a runtime bone driver sees identity.
KK_ChaFileCustomBody.json Body-customization values: shape sliders, skin/detail IDs and colors, bust softness/weight.
KK_CharacterInfoData.json Character name plus face/eye parameters: personality, pupil size / offset / scale, and eye-highlight offsets.
KK_BlendShapeInfo.json Expression blendshape patterns (Eye / Mouth / …) mapping each named expression to the raw PMX morphs the converter combines.
KK_AibuHitColliderData.json H-scene "Aibu" touch-zone colliders: name, tag / body zone, collider type, and local transform.

In-game options

The exporter panel exposes: Export All Outfits, Enable Pushups, Lean export (kkunity only), Bulk export all cards in folder, and the Export Model for kkunity button.

  • Lean export (default on) ships only what the converter reads — per-material _AM (alpha mask) and _NMP (normal) textures plus the per-coordinate body _AM, and the 12 sidecars above — skipping the bulk of raw texture maps and 11 legacy sidecars. Turn it off for a full dump.
  • Enable Pushups captures a per-outfit body morph so each coordinate's pushup is reproducible on the shared body.

Building

Visual Studio / dotnet build against the .sln, with two configurations:

Config Framework Game Accessory DLLs (in deps/)
NET35 net35 Koikatsu (KK) KK_Accessory_States.dll, KK_Pushup.dll
NET46 net46 Koikatsu Sunshine (KKS) KKS_Accessory_States.dll, KKS_Pushup.dll
# Koikatsu Sunshine
dotnet build kkunity_plugin\kkunity_plugin.sln -c NET46
# Koikatsu
dotnet build kkunity_plugin\kkunity_plugin.sln -c NET35

Game/BepInEx assemblies come from NuGet (IllusionLibs.*, BepInEx, IllusionModdingAPI). The KK*_Accessory_States / KK*_Pushup reference DLLs are not redistributed here — drop them in kkunity_plugin/deps/ (see the placeholder file there). create_release.bat packages both DLLs into a release zip.


Part 2 — The converter (kkunity_converter/)

Input

Point the converter at an export folder produced by the plugin:

<export>/
  model.pmx                  body mesh + full skeleton + face morphs
  KK_*.json                  material / bone / blendshape / texture sidecars
  baked materials/           one composited albedo PNG per body/face/eye material
  cf_m_body_AM*.png          per-coordinate body alpha masks
  cf_m_*_NMP.png             raw (packed) normal maps
  Outfit 00/
    model.pmx                that coordinate's clothing + hair
    baked materials/         composited albedo for this outfit's materials
    screenshot.png           preview (used by the GUI)
  Outfit 01/ ...             one folder per coordinate

Each material's base color comes from the baked materials/ composite (the exporter's flattened albedo). The gag-eye and tears overlays aren't composited there, so they fall back to their raw _MT_CT.png.

Output

Modes:

  • Single GLB (CLI default): one .glb with textures embedded. Self-contained, good for quick viewing / generic glTF tools.
  • Unity export (--unity-export / --fbx / --kkm): a <char>.glb — or, with --fbx, a binary <char>.fbx converted from the same built GLB (identical geometry/rig/blendshapes) — with no embedded textures, plus loose sidecar files the Unity runtime loader rebuilds materials from:
    • <char>.ht — Unity HumanTemplate with the humanoid bone mapping (in the editor's Avatar Configuration use Mapping → Load to apply it)
    • <material>.png / .jpg — per-material main textures (deduplicated by content; a KK_TextureManifest.json aliases duplicates back to the one file that was actually written)
    • <material>_NMP.png — raw normal maps, shipped byte-for-byte
    • KK_*.json — the sidecars the loader and its components consume
    • <char>_Outfit_NN_body_AlphaMask.png — per-coordinate body masks
    • with --kkm (GLB-based), everything is zipped into a flat <char>.kkm and the loose files are removed — only the bundle remains.

Usage

GUI

run_gui.bat

Pick an export folder; if it has multiple outfits, check which to export (thumbnails come from each outfit's screenshots). Pick the output Format.kkm bundle (packed, no loose files, the default), GLB + sidecar files, or FBX + sidecar files — toggle the options, pick an output folder, and Export. Other GUI defaults: Ground feet on, Blank unused atlas regions on, JPEG opaque textures off, Include gag eyes & tears off (JPEG quality is fixed at 90).

CLI

# single embedded-texture GLB
python convert.py "path\to\export" -o output\model.glb

# loose unity_export folder (GLB + sidecars)
python convert.py "path\to\export" --unity-export -o output\char

# loose unity_export folder with an FBX instead of the GLB
python convert.py "path\to\export" --fbx -o output\char

# packed .kkm (loose files removed after packing)
python convert.py "path\to\export" --kkm -o output\char

Options:

flag effect
--unity-export emit the loose folder instead of a single GLB
--fbx ship the loose folder's model as a binary FBX instead of a GLB (implies --unity-export; incompatible with --kkm)
--kkm zip the folder into <char>.kkm and remove the loose files (implies --unity-export; GLB-based)
--jpeg-opaque ship opaque textures as JPEG (~85% smaller); textures with real transparency stay PNG
--jpeg-quality N JPEG quality for --jpeg-opaque (default 90)
--mask-unused flatten atlas texels a material's UVs never cover, so a material on a sliver of a shared 4096² sheet stops shipping the whole sheet
--no-ground-feet keep KK's original height (don't drop the rig so the feet rest on the floor)
--gag-tears include the gag-eye / tears overlay meshes and their shape keys (off by default)

How it works

kkunity_converter/
  read_export/   parse the PMX + KK_*.json + locate textures
  mesh/          combine partial PMX morphs into named blendshapes; build the
                 gag/tears reveal + per-outfit pushup morphs
  armature/      reduce the raw skeleton, rename to Unity humanoid, orient bones
                 to the game frame from EditBoneInfo
  export/        composite/grade/mask textures and write the GLB/FBX + unity_export

read_export — A from-scratch PMX 2.0/2.1 reader (parse_pmxPMX: vertices with skin weights and extra UVs, faces, materials with their face spans, bones, vertex morphs) and an ExportFolder helper that resolves the JSON sidecars, the baked materials/ composites, normal maps, and per-material shader properties (alpha-mask transforms, clothing-state floats, the _AlphaMaskuv UV set).

meshcombine_morphs merges the partial vertex morphs into named expression blendshapes following KK_BlendShapeInfo.json (with the eye/mouth filtering rules), build_pushup_morphs builds the per-outfit pushup morphs, and build_tear_gag_morphs / build_gag_eye_hide reproduce the gag-eye / tears visibility trick in morph space: the overlays are pushed back into the head at rest and a reveal morph moves them forward.

armaturereduce_skeleton cuts the raw PMX skeleton to a clean body rig (drops IK-target cf_t_*, clothing-parent ct_* and outfit object-root pseudo-bones o_*/n_*/clothes_*; promotes Center/Hips to roots), rename_bones maps bones to the Unity humanoid convention (deduping name collisions by appending _0, _1, … suffixes), and orient_skeleton re-orients each bone to the game's bone frame from KK_EditBoneInfo.json so a runtime expression-bone driver sees an identity correction.

export

  • Textures (lut.py, unity_export.py): sources each material's baked materials/ composite, applies KK's Amplify Color LUT grade (vendored as the pre-baked amplify_lut_table.npy), bakes clothing/bra alpha masks into the texture alpha by rasterizing the mask through the mesh (the mask is sampled in a second UV set, so it can't be combined in texture space), and dedups identical images by content (blake2b hash → KK_TextureManifest.json). Normal maps ship verbatim (any pixel touch would corrupt the packed X/Y encoding).
  • GLB (glb.py, build_glb): one self-contained, deduplicated mesh per group (Body / Hair / Outfit / Gag / Tears) with its own vertex buffer, sparse morph targets, and a shared skin; PMX (left-handed) is converted to glTF (right-handed) by negating Z and reversing winding; the rig is optionally grounded so the feet rest on the floor.
  • FBX (fbx.py, glb_to_fbx): a pure-Python binary FBX 7.4 writer that translates the finished GLB — same hierarchy, skin clusters, and blendshape channels — using the Blender-style convention Unity expects (Y-up, centimeters, UnitScaleFactor 1). Materials are name-only; textures come from the sidecars, same as the GLB path.

Setup

python -m venv .venv
.\.venv\Scripts\Activate.ps1
pip install -r requirements.txt

Requires Python 3.10+ (uses X | Y type syntax). Core dependencies: numpy, Pillow, scipy, pygltflib.


Scope

This targets a clean, animation-ready Unity avatar export: geometry, skinning, blendshapes, materials, and the dynamic-bone / collider sidecars the runtime loader wires up.