- 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
115 lines
5.7 KiB
Python
115 lines
5.7 KiB
Python
import bpy
|
|
from ..interface.dictionary_en import t
|
|
from .. import common as c
|
|
|
|
class mat_comb_setup(bpy.types.Operator):
|
|
bl_idname = "kkbp.matcombsetup"
|
|
bl_label = "Material combiner setup"
|
|
bl_description = t('mat_comb_tt')
|
|
bl_options = {'REGISTER', 'UNDO'}
|
|
|
|
def execute(self, context):
|
|
def recurLayerCollection(layerColl, collName):
|
|
found = None
|
|
if (layerColl.name == collName):
|
|
return layerColl
|
|
for layer in layerColl.children:
|
|
found = recurLayerCollection(layer, collName)
|
|
if found:
|
|
return found
|
|
|
|
def remove_orphan_data():
|
|
#revert the image back from the atlas file to the baked file
|
|
for mat in bpy.data.materials:
|
|
if mat.name[-4:] == '-ORG':
|
|
simplified_name = mat.name[:-4]
|
|
if bpy.data.materials.get(simplified_name):
|
|
simplified_mat = bpy.data.materials[simplified_name]
|
|
for bake_type in ['light', 'dark', 'normal']:
|
|
simplified_mat.node_tree.nodes['textures'].node_tree.nodes[bake_type].image = bpy.data.images.get(simplified_name + ' ' + bake_type + '.png')
|
|
#delete orphan data
|
|
for cat in [bpy.data.armatures, bpy.data.objects, bpy.data.meshes, bpy.data.materials, bpy.data.images, bpy.data.node_groups]:
|
|
for block in cat:
|
|
if block.users == 0:
|
|
cat.remove(block)
|
|
|
|
if bpy.data.collections.get(c.get_name() + ' atlas'):
|
|
c.kklog('deleting previous collection "Model with atlas" and regenerating atlas model...')
|
|
def del_collection(coll):
|
|
for c in coll.children:
|
|
del_collection(c)
|
|
bpy.data.collections.remove(coll,do_unlink=True)
|
|
del_collection(bpy.data.collections[c.get_name() + ' atlas'])
|
|
remove_orphan_data()
|
|
#show the original collection again
|
|
layer_collection = bpy.context.view_layer.layer_collection
|
|
layerColl = recurLayerCollection(layer_collection, 'Scene Collection')
|
|
bpy.context.view_layer.active_layer_collection = layerColl
|
|
bpy.context.scene.view_layers[0].active_layer_collection.children[0].exclude = False
|
|
|
|
#Change the Active LayerCollection to 'My Collection'
|
|
layer_collection = bpy.context.view_layer.layer_collection
|
|
layerColl = recurLayerCollection(layer_collection, c.get_name())
|
|
bpy.context.view_layer.active_layer_collection = layerColl
|
|
|
|
# https://blender.stackexchange.com/questions/157828/how-to-duplicate-a-certain-collection-using-python
|
|
from collections import defaultdict
|
|
def copy_objects(from_col, to_col, linked, dupe_lut):
|
|
for o in from_col.objects:
|
|
dupe = o.copy()
|
|
if not linked and o.data:
|
|
dupe.data = dupe.data.copy()
|
|
to_col.objects.link(dupe)
|
|
dupe_lut[o] = dupe
|
|
def copy(parent, collection, linked=False):
|
|
dupe_lut = defaultdict(lambda : None)
|
|
def _copy(parent, collection, linked=False):
|
|
if collection.name == 'Bone Widgets':
|
|
return
|
|
cc = bpy.data.collections.new(collection.name)
|
|
copy_objects(collection, cc, linked, dupe_lut)
|
|
for c in collection.children:
|
|
_copy(cc, c, linked)
|
|
parent.children.link(cc)
|
|
_copy(parent, collection, linked)
|
|
for o, dupe in tuple(dupe_lut.items()):
|
|
parent = dupe_lut[o.parent]
|
|
if parent:
|
|
dupe.parent = parent
|
|
|
|
context = bpy.context
|
|
scene = context.scene
|
|
col = context.collection
|
|
assert(col is not scene.collection)
|
|
copy(scene.collection, col)
|
|
|
|
#setup materials for the combiner script
|
|
for obj in [o for o in bpy.data.collections[c.get_name() + '.001'].all_objects if not o.hide_get() and o.type == 'MESH']:
|
|
for mat in [mat_slot.material for mat_slot in obj.material_slots if mat_slot.material.get('simple')]:
|
|
nodes = mat.node_tree.nodes
|
|
links = mat.node_tree.links
|
|
emissive_node = nodes.new('ShaderNodeEmission')
|
|
image_node = nodes.new('ShaderNodeTexImage')
|
|
links.new(emissive_node.inputs[0], image_node.outputs[0])
|
|
image_node.image = nodes['textures'].node_tree.nodes['light'].image
|
|
context.view_layer.objects.active = obj
|
|
bpy.ops.object.material_slot_remove_unused()
|
|
|
|
#update the modifiers
|
|
for mod in obj.modifiers:
|
|
if mod.type == 'ARMATURE':
|
|
#fix the armature modifier to use the copied aramture
|
|
copied_armature = [o for o in bpy.data.collections[c.get_name() + '.001'].all_objects if o.type == 'ARMATURE'][0]
|
|
mod.object = copied_armature
|
|
elif mod.type == 'SOLIDIFY':
|
|
#disable the outline on the atlased object because I don't feel like fixing it
|
|
obj.modifiers['Outline Modifier'].show_render = False
|
|
obj.modifiers['Outline Modifier'].show_viewport = False
|
|
elif mod.type == 'UV_WARP':
|
|
#fix the UV warp modifier to use the copied armature
|
|
copied_armature = [o for o in bpy.data.collections[c.get_name() + '.001'].all_objects if o.type == 'ARMATURE'][0]
|
|
mod.object_from = copied_armature
|
|
mod.object_to = copied_armature
|
|
|
|
return {'FINISHED'}
|