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:
71
exporting/material_combiner/combiner.py
Normal file
71
exporting/material_combiner/combiner.py
Normal file
@@ -0,0 +1,71 @@
|
||||
import bpy
|
||||
from bpy.props import *
|
||||
from .combiner_ops import *
|
||||
from .packer import BinPacker
|
||||
from ... import common as c
|
||||
|
||||
class Combiner(bpy.types.Operator):
|
||||
bl_idname = 'kkbp.combiner'
|
||||
bl_label = 'Create Atlas'
|
||||
bl_description = 'Combine materials'
|
||||
bl_options = {'UNDO', 'INTERNAL'}
|
||||
|
||||
def execute(self, context: bpy.types.Context) -> Set[str]:
|
||||
#from invoke
|
||||
scn = context.scene
|
||||
bpy.ops.kkbp.refresh_ob_data()
|
||||
for index, object in enumerate([o for o in bpy.data.collections[c.get_name() + ' atlas'].all_objects if o.type == 'MESH' and not o.hide_get()]):
|
||||
#check if this object is worth doing anything with
|
||||
if not [mat_slot.material for mat_slot in object.material_slots if mat_slot.material.get('simple')]:
|
||||
continue
|
||||
|
||||
set_ob_mode(context.view_layer, scn.kkbp_ob_data)
|
||||
self.data = get_data(scn.kkbp_ob_data, object)
|
||||
self.mats_uv = get_mats_uv(scn, self.data)
|
||||
clear_empty_mats(scn, self.data, self.mats_uv)
|
||||
get_duplicates(self.mats_uv)
|
||||
self.structure = get_structure(scn, self.data, self.mats_uv)
|
||||
|
||||
#from execute
|
||||
scn.kkbp_save_path = os.path.join(context.scene.kkbp.import_dir, 'atlas_files')
|
||||
self.structure = BinPacker(get_size(scn, self.structure)).fit()
|
||||
|
||||
size = get_atlas_size(self.structure)
|
||||
atlas_size = calculate_adjusted_size(scn, size)
|
||||
|
||||
if max(atlas_size, default=0) > 20000:
|
||||
text = 'The output image size of {0}x{1}px is too large'.format(*atlas_size)
|
||||
c.kklog(text)
|
||||
self.report({'ERROR'}, text)
|
||||
return {'FINISHED'}
|
||||
|
||||
bake_types = []
|
||||
if scn.kkbp.bake_light_bool:
|
||||
bake_types.append('light')
|
||||
if scn.kkbp.bake_dark_bool:
|
||||
bake_types.append('dark')
|
||||
if scn.kkbp.bake_norm_bool:
|
||||
bake_types.append('normal')
|
||||
|
||||
for type in bake_types:
|
||||
#replace all images
|
||||
for material in [mat_slot.material for mat_slot in object.material_slots if mat_slot.material.get('simple')]:
|
||||
image = material.node_tree.nodes['textures'].node_tree.nodes[type].image
|
||||
if image:
|
||||
if image.name == 'Template: Placeholder':
|
||||
image = None
|
||||
if not image:
|
||||
continue
|
||||
else:
|
||||
material.node_tree.nodes['Image Texture'].image = image
|
||||
|
||||
#then run the atlas creation
|
||||
atlas = get_atlas(scn, self.structure, atlas_size)
|
||||
comb_mats = get_comb_mats(scn, atlas, self.mats_uv, type, index)
|
||||
c.print_timer(f'save atlas for {object.name} {type}')
|
||||
|
||||
align_uvs(scn, self.structure, atlas.size, size)
|
||||
bpy.ops.kkbp.refresh_ob_data()
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
Reference in New Issue
Block a user