feat: Add KoikatsuBlenderPipeline addon with import/export functionality

- Add core addon files (__init__.py, KKPanel.py, preferences.py, common.py)
- Add import pipeline with armature, mesh, and material modification modules
- Add export pipeline with material baking and FBX preparation utilities
- Add material combiner tool for texture atlas generation and optimization
- Add extras utilities for animation, rigging, and asset management
- Add bone orientation data from better_fbx for accurate skeletal structure
- Add comprehensive documentation and wiki with multi-language support (EN, JP, ZH)
- Add animation library retargeting lists for ARP and Rokoko motion capture
- Add Rigify integration scripts for advanced rigging workflows
- Add shader file (KK Shader V8.0.blend) for material rendering
- Add manifest and license files for addon distribution
- Add changelog documenting version history and improvements
- Initialize complete Blender addon project for Koikatsu character import/export
This commit is contained in:
2025-12-06 15:26:19 +08:00
commit 5d9e09e9c3
122 changed files with 22683 additions and 0 deletions

99
extras/linkshapekeys.py Normal file
View File

@@ -0,0 +1,99 @@
'''
LINK EYEBROW SHAPEKEYS TO BODY SCRIPT
Usage:
- Seperate the eyebrow mesh into its own object
- Select the eyebrows object, then shift click the body object and run the script to control the eyebrow shapekeys from the body object
Script 90% stolen from https://blender.stackexchange.com/questions/86757/python-how-to-connect-shapekeys-via-drivers
'''
import bpy
from ..interface.dictionary_en import t
from .. import common as c
def link_keys(shapekey_holder_object, objects_to_link):
shapekey_list_string = str(shapekey_holder_object.data.shape_keys.key_blocks.keys()).lower()
for obj in objects_to_link:
bpy.ops.object.select_all(action = 'DESELECT')
bpy.context.view_layer.objects.active = obj
obj.select_set(True)
bpy.ops.object.material_slot_remove_unused()
for key in obj.data.shape_keys.key_blocks:
if key.name.lower() in shapekey_list_string:
if not key.name == obj.data.shape_keys.key_blocks[0]:
skey_driver = key.driver_add('value')
skey_driver.driver.type = 'AVERAGE'
#skey_driver.driver.show_debug_info = True
if skey_driver.driver.variables:
for v in skey_driver.driver.variables:
skey_driver.driver.variables.remove(v)
newVar = skey_driver.driver.variables.new()
newVar.name = "value"
newVar.type = 'SINGLE_PROP'
newVar.targets[0].id_type = 'KEY'
newVar.targets[0].id = shapekey_holder_object.data.shape_keys
newVar.targets[0].data_path = 'key_blocks["' + key.name+ '"].value'
skey_driver = key.driver_add('mute')
skey_driver.driver.type = 'AVERAGE'
#skey_driver.driver.show_debug_info = True
if skey_driver.driver.variables:
for v in skey_driver.driver.variables:
skey_driver.driver.variables.remove(v)
newVar = skey_driver.driver.variables.new()
newVar.name = "hide"
newVar.type = 'SINGLE_PROP'
newVar.targets[0].id_type = 'KEY'
newVar.targets[0].id = shapekey_holder_object.data.shape_keys
newVar.targets[0].data_path = 'key_blocks["' + key.name+ '"].mute'
class link_shapekeys(bpy.types.Operator):
bl_idname = "kkbp.linkshapekeys"
bl_label = "Link shapekeys"
bl_description = t('sep_eye_tt')
bl_options = {'REGISTER', 'UNDO'}
def execute(self, context):
#separate the eyes from the body object
body = c.get_body()
c.switch(body, 'EDIT')
def separateMaterial(matList):
for mat in matList:
try:
def moveUp():
return bpy.ops.object.material_slot_move(direction='UP')
while moveUp() != {"CANCELLED"}:
pass
bpy.context.object.active_material_index = body.data.materials.find(mat)
bpy.ops.object.material_slot_select()
except:
print('material wasn\'t found: ' + mat)
bpy.ops.mesh.separate(type='SELECTED')
eye_list = ['KK EyeR (hitomi) ' + c.get_name(),
'KK EyeL (hitomi) ' + c.get_name(),
'KK Eyewhites (sirome) ' + c.get_name(),
'KK Eyeline up ' + c.get_name(),
'KK Eyeline down ' + c.get_name()]
separateMaterial(eye_list)
eyes = bpy.data.objects[body.name + '.001']
eyes.name = 'Eyes'
if eyes.modifiers.get('Outline Modifier'):
eyes.modifiers['Outline Modifier'].show_viewport = False
eyes.modifiers['Outline Modifier'].show_render = False
#do the same for the eyebrows
separateMaterial(['KK Eyebrows (mayuge) ' + c.get_name()])
eyebrows = bpy.data.objects[body.name + '.001']
eyebrows.name = 'Eyebrows'
if eyebrows.modifiers.get('Outline Modifier'):
eyebrows.modifiers['Outline Modifier'].show_viewport = False
eyebrows.modifiers['Outline Modifier'].show_render = False
bpy.ops.object.mode_set(mode = 'OBJECT')
link_keys(body, [eyes, eyebrows])
return {'FINISHED'}