First Commit

This commit is contained in:
2026-04-08 11:47:23 +02:00
committed by GitHub
parent 67b5d118c2
commit 96d567eb9e
11 changed files with 1050 additions and 0 deletions

156
operators/mmd.py Normal file
View File

@@ -0,0 +1,156 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import bpy
from utilities.constants import MMD_VISEME_COUNT, MMD_SEP_1, MMD_SEP_2
from utilities.functions import MMD_JP_MAPPING
from utilities.helpers import _ps, guess_shape, _restore_shapekey_values
class VRCVIS_OT_MMDAutoDetect(bpy.types.Operator):
bl_idname = 'vrc_viseme.mmd_auto_detect'
bl_label = 'Auto-rileva (EN → JP)'
bl_description = (
'Cerca automaticamente i nomi inglesi/VRChat comuni e precompila '
'i campi di destinazione MMD giapponese'
)
bl_options = {'REGISTER', 'UNDO'}
def execute(self, context):
scene = context.scene
mesh_name = scene.vrcvis_mesh
if not mesh_name or mesh_name not in bpy.data.objects:
self.report({'ERROR'}, 'Nessuna mesh selezionata')
return {'CANCELLED'}
obj = bpy.data.objects[mesh_name]
found = 0
for _jp, suffix, _en, candidates in MMD_JP_MAPPING:
result = guess_shape(obj, candidates)
if result:
setattr(scene, f'vrcvis_mmd_{suffix}', result)
found += 1
if found:
self.report({'INFO'}, f'Rilevate {found} shape key')
else:
self.report({'WARNING'}, 'Nessun nome riconosciuto trovato')
return {'FINISHED'}
class VRCVIS_OT_MMDConvert(bpy.types.Operator):
bl_idname = 'vrc_viseme.mmd_convert'
bl_label = 'Converti in MMD'
bl_description = (
'Duplica le shape key selezionate con i nomi MMD giapponesi, '
'aggiunge i separatori e posiziona tutto in fondo alla lista'
)
bl_options = {'REGISTER', 'UNDO'}
def execute(self, context):
scene = context.scene
mesh_name = scene.vrcvis_mesh
if not mesh_name or mesh_name not in bpy.data.objects:
self.report({'ERROR'}, 'Seleziona una mesh valida')
return {'CANCELLED'}
obj = bpy.data.objects[mesh_name]
if not obj.data.shape_keys:
self.report({'ERROR'}, 'La mesh non ha shape key')
return {'CANCELLED'}
if _ps.active:
_restore_shapekey_values(obj)
_ps.active = False
scene.vrcvis_preview_active = False
bpy.context.view_layer.objects.active = obj
obj.select_set(True)
obj.show_only_shape_key = False
keys = obj.data.shape_keys.key_blocks
overwrite = scene.vrcvis_overwrite
created = []
skipped = []
def _add_empty(name):
if name in keys:
if overwrite:
obj.active_shape_key_index = keys.find(name)
bpy.ops.object.shape_key_remove()
else:
skipped.append(name)
return
bpy.ops.object.shape_key_clear()
obj.shape_key_add(name=name, from_mix=True)
created.append(name)
def _add_copy(src_name, dst_name):
if not src_name or src_name not in keys:
return
if dst_name in keys:
if overwrite:
obj.active_shape_key_index = keys.find(dst_name)
bpy.ops.object.shape_key_remove()
else:
skipped.append(dst_name)
return
bpy.ops.object.shape_key_clear()
keys[src_name].slider_max = max(keys[src_name].slider_max, 1.0)
keys[src_name].value = 1.0
obj.shape_key_add(name=dst_name, from_mix=True)
bpy.ops.object.shape_key_clear()
created.append(dst_name)
_add_empty(MMD_SEP_1)
for jp_name, suffix, _en, _ in MMD_JP_MAPPING[:MMD_VISEME_COUNT]:
src = getattr(scene, f'vrcvis_mmd_{suffix}')
_add_copy(src, jp_name)
_add_empty(MMD_SEP_2)
for jp_name, suffix, _en, _ in MMD_JP_MAPPING[MMD_VISEME_COUNT:]:
src = getattr(scene, f'vrcvis_mmd_{suffix}')
_add_copy(src, jp_name)
obj.active_shape_key_index = 0
msg_parts = []
if created:
msg_parts.append(f'Create: {len(created)}')
if skipped:
msg_parts.append(f'Saltate: {len(skipped)}')
self.report({'INFO'}, ' | '.join(msg_parts) if msg_parts else 'Nessuna shape key creata')
return {'FINISHED'}
class VRCVIS_OT_MMDRemove(bpy.types.Operator):
bl_idname = 'vrc_viseme.mmd_remove'
bl_label = 'Rimuovi MMD'
bl_description = (
'Rimuove le shape key MMD giapponesi e i separatori '
'(---MMD Visemes--- e ^MMD Visemes / Other v)'
)
bl_options = {'REGISTER', 'UNDO'}
def execute(self, context):
scene = context.scene
mesh_name = scene.vrcvis_mesh
if not mesh_name or mesh_name not in bpy.data.objects:
self.report({'ERROR'}, 'Nessuna mesh selezionata')
return {'CANCELLED'}
obj = bpy.data.objects[mesh_name]
if not obj.data.shape_keys:
self.report({'INFO'}, 'Nessuna shape key presente')
return {'FINISHED'}
bpy.context.view_layer.objects.active = obj
obj.select_set(True)
mmd_names = {jp for jp, _, _en, _ in MMD_JP_MAPPING} | {MMD_SEP_1, MMD_SEP_2}
to_remove = [k.name for k in obj.data.shape_keys.key_blocks if k.name in mmd_names]
count = 0
for name in to_remove:
keys = obj.data.shape_keys.key_blocks
if name in keys:
obj.active_shape_key_index = keys.find(name)
bpy.ops.object.shape_key_remove()
count += 1
self.report({'INFO'}, f'Rimosse {count} shape key MMD')
return {'FINISHED'}