Added Eye tracking and Visemes

This commit is contained in:
Yusarina
2024-12-15 20:14:26 +00:00
parent f4dc74d091
commit 87a351cea4
13 changed files with 1807 additions and 39 deletions
+143
View File
@@ -0,0 +1,143 @@
import bpy
from typing import Set
from bpy.types import Panel, Context, UILayout, Operator
from .main_panel import AvatarToolKit_PT_AvatarToolkitPanel, CATEGORY_NAME
from ..core.translations import t
from ..core.common import get_active_armature, get_all_meshes
from ..functions.eye_tracking import (
CreateEyesButton,
StartTestingButton,
StopTestingButton,
ResetRotationButton,
AdjustEyesButton,
TestBlinking,
TestLowerlid,
ResetBlinkTest,
ResetEyeTrackingButton,
RotateEyeBonesForAv3Button
)
class AvatarToolKit_PT_EyeTrackingPanel(Panel):
"""Panel containing eye tracking setup and testing tools"""
bl_label = t("EyeTracking.label")
bl_idname = "VIEW3D_PT_avatar_toolkit_eye_tracking"
bl_space_type = 'VIEW_3D'
bl_region_type = 'UI'
bl_category = CATEGORY_NAME
bl_parent_id = AvatarToolKit_PT_AvatarToolkitPanel.bl_idname
bl_order = 3
bl_options = {'DEFAULT_CLOSED'}
def draw(self, context: Context) -> None:
"""Draw the eye tracking panel interface"""
layout = self.layout
toolkit = context.scene.avatar_toolkit
# Mode Selection Box
mode_box = layout.box()
col = mode_box.column(align=True)
col.label(text=t("EyeTracking.mode_select"), icon='TOOL_SETTINGS')
col.separator(factor=0.5)
col.prop(toolkit, "eye_mode", expand=True)
if toolkit.eye_mode == 'CREATION':
# Mesh Setup Box
mesh_box = layout.box()
col = mesh_box.column(align=True)
col.label(text=t("EyeTracking.mesh_setup"), icon='MESH_DATA')
col.separator(factor=0.5)
col.prop(toolkit, "mesh_name_eye", text="")
# Bone Setup Box
bone_box = layout.box()
col = bone_box.column(align=True)
col.label(text=t("EyeTracking.bone_setup"), icon='BONE_DATA')
col.separator(factor=0.5)
armature = get_active_armature(context)
if armature:
col.prop_search(toolkit, "head", armature.data, "bones", text=t("EyeTracking.head_bone"))
col.prop_search(toolkit, "eye_left", armature.data, "bones", text=t("EyeTracking.eye_left"))
col.prop_search(toolkit, "eye_right", armature.data, "bones", text=t("EyeTracking.eye_right"))
else:
col.label(text=t("EyeTracking.no_armature"), icon='ERROR')
# Shapekey Setup Box
shape_box = layout.box()
col = shape_box.column(align=True)
col.label(text=t("EyeTracking.shapekey_setup"), icon='SHAPEKEY_DATA')
col.separator(factor=0.5)
mesh = bpy.data.objects.get(toolkit.mesh_name_eye)
if mesh and mesh.data.shape_keys:
col.prop_search(toolkit, "wink_left", mesh.data.shape_keys, "key_blocks", text=t("EyeTracking.wink_left"))
col.prop_search(toolkit, "wink_right", mesh.data.shape_keys, "key_blocks", text=t("EyeTracking.wink_right"))
col.prop_search(toolkit, "lowerlid_left", mesh.data.shape_keys, "key_blocks", text=t("EyeTracking.lowerlid_left"))
col.prop_search(toolkit, "lowerlid_right", mesh.data.shape_keys, "key_blocks", text=t("EyeTracking.lowerlid_right"))
else:
col.label(text=t("EyeTracking.no_shapekeys"), icon='ERROR')
# Options Box
options_box = layout.box()
col = options_box.column(align=True)
col.label(text=t("EyeTracking.options"), icon='SETTINGS')
col.separator(factor=0.5)
col.prop(toolkit, "disable_eye_blinking")
col.prop(toolkit, "disable_eye_movement")
if not toolkit.disable_eye_movement:
col.prop(toolkit, "eye_distance")
# Create Button
row = layout.row(align=True)
row.scale_y = 1.5
row.operator(CreateEyesButton.bl_idname, icon='PLAY')
else:
if context.mode != 'POSE':
# Testing Start Box
test_box = layout.box()
col = test_box.column(align=True)
col.label(text=t("EyeTracking.testing"), icon='PLAY')
col.separator(factor=0.5)
row = col.row(align=True)
row.scale_y = 1.5
row.operator(StartTestingButton.bl_idname, icon='PLAY')
else:
# Eye Rotation Box
rotation_box = layout.box()
col = rotation_box.column(align=True)
col.label(text=t("EyeTracking.rotation_controls"), icon='DRIVER_ROTATIONAL_DIFFERENCE')
col.separator(factor=0.5)
col.prop(toolkit, "eye_rotation_x", text=t("EyeTracking.rotation.x"))
col.prop(toolkit, "eye_rotation_y", text=t("EyeTracking.rotation.y"))
col.operator(ResetRotationButton.bl_idname, icon='LOOP_BACK')
# Eye Adjustment Box
adjust_box = layout.box()
col = adjust_box.column(align=True)
col.label(text=t("EyeTracking.adjustments"), icon='MODIFIER')
col.separator(factor=0.5)
col.prop(toolkit, "eye_distance")
col.operator(AdjustEyesButton.bl_idname, icon='CON_TRACKTO')
# Blinking Test Box
blink_box = layout.box()
col = blink_box.column(align=True)
col.label(text=t("EyeTracking.blink_testing"), icon='HIDE_OFF')
col.separator(factor=0.5)
row = col.row(align=True)
row.prop(toolkit, "eye_blink_shape")
row.operator(TestBlinking.bl_idname, icon='RESTRICT_VIEW_OFF')
row = col.row(align=True)
row.prop(toolkit, "eye_lowerlid_shape")
row.operator(TestLowerlid.bl_idname, icon='RESTRICT_VIEW_OFF')
col.operator(ResetBlinkTest.bl_idname, icon='LOOP_BACK')
# Stop Testing Button
row = layout.row(align=True)
row.scale_y = 1.5
row.operator(StopTestingButton.bl_idname, icon='PAUSE')
# Reset Button
row = layout.row(align=True)
row.operator(ResetEyeTrackingButton.bl_idname, icon='FILE_REFRESH')
-1
View File
@@ -31,7 +31,6 @@ class AvatarToolKit_PT_AvatarToolkitPanel(Panel):
bl_space_type: str = 'VIEW_3D'
bl_region_type: str = 'UI'
bl_category: str = CATEGORY_NAME
bl_options: Set[str] = {'DEFAULT_CLOSED'}
def draw(self, context: Context) -> None:
"""Draw the main panel layout"""
+41 -38
View File
@@ -1,46 +1,49 @@
import bpy
from typing import Set
from bpy.types import Panel, Context, UILayout
from .main_panel import AvatarToolKit_PT_AvatarToolkitPanel, CATEGORY_NAME
from ..core.translations import t
# MMD Tools disabled for the time being unto it can be fixed.
class AvatarToolKit_PT_MMDPanel(Panel):
"""Panel containing MMD bone standardization and cleanup tools"""
bl_label = t("MMD.label")
bl_idname = "OBJECT_PT_avatar_toolkit_mmd"
bl_space_type = 'VIEW_3D'
bl_region_type = 'UI'
bl_category = CATEGORY_NAME
bl_parent_id = AvatarToolKit_PT_AvatarToolkitPanel.bl_idname
bl_order = 3
# import bpy
# from typing import Set
# from bpy.types import Panel, Context, UILayout
# from .main_panel import AvatarToolKit_PT_AvatarToolkitPanel, CATEGORY_NAME
# from ..core.translations import t
def draw(self, context: Context) -> None:
layout: UILayout = self.layout
toolkit = context.scene.avatar_toolkit
# class AvatarToolKit_PT_MMDPanel(Panel):
# """Panel containing MMD bone standardization and cleanup tools"""
# bl_label = t("MMD.label")
# bl_idname = "OBJECT_PT_avatar_toolkit_mmd"
# bl_space_type = 'VIEW_3D'
# bl_region_type = 'UI'
# bl_category = CATEGORY_NAME
# bl_parent_id = AvatarToolKit_PT_AvatarToolkitPanel.bl_idname
# bl_order = 3
# bl_options = {'DEFAULT_CLOSED'}
# def draw(self, context: Context) -> None:
# layout: UILayout = self.layout
# toolkit = context.scene.avatar_toolkit
# Bone Settings Box
bone_box: UILayout = layout.box()
col: UILayout = bone_box.column(align=True)
col.label(text=t("MMD.bone_settings"), icon='BONE_DATA')
col.separator(factor=0.5)
col.prop(toolkit, "keep_twist_bones")
col.prop(toolkit, "keep_upper_chest")
col.operator("avatar_toolkit.standardize_mmd", icon='BONE_DATA')
# bone_box: UILayout = layout.box()
# col: UILayout = bone_box.column(align=True)
# col.label(text=t("MMD.bone_settings"), icon='BONE_DATA')
# col.separator(factor=0.5)
# col.prop(toolkit, "keep_twist_bones")
# col.prop(toolkit, "keep_upper_chest")
# col.operator("avatar_toolkit.standardize_mmd", icon='BONE_DATA')
# Mesh Tools Box
mesh_box: UILayout = layout.box()
col = mesh_box.column(align=True)
col.label(text=t("MMD.mesh_tools"), icon='MESH_DATA')
col.separator(factor=0.5)
row: UILayout = col.row(align=True)
row.operator("avatar_toolkit.fix_meshes", icon='MODIFIER')
row.operator("avatar_toolkit.validate_meshes", icon='CHECKMARK')
# mesh_box: UILayout = layout.box()
# col = mesh_box.column(align=True)
# col.label(text=t("MMD.mesh_tools"), icon='MESH_DATA')
# col.separator(factor=0.5)
# row: UILayout = col.row(align=True)
# row.operator("avatar_toolkit.fix_meshes", icon='MODIFIER')
# row.operator("avatar_toolkit.validate_meshes", icon='CHECKMARK')
# Cleanup Box
cleanup_box: UILayout = layout.box()
col = cleanup_box.column(align=True)
col.label(text=t("MMD.cleanup"), icon='BRUSH_DATA')
col.separator(factor=0.5)
col.operator("avatar_toolkit.cleanup_mmd", icon='SHADERFX')
col.operator("avatar_toolkit.convert_mmd_morphs", icon='SHAPEKEY_DATA')
col.operator("avatar_toolkit.reparent_meshes", icon='OUTLINER_OB_ARMATURE')
# cleanup_box: UILayout = layout.box()
# col = cleanup_box.column(align=True)
# col.label(text=t("MMD.cleanup"), icon='BRUSH_DATA')
# col.separator(factor=0.5)
# col.operator("avatar_toolkit.cleanup_mmd", icon='SHADERFX')
# col.operator("avatar_toolkit.convert_mmd_morphs", icon='SHAPEKEY_DATA')
# col.operator("avatar_toolkit.reparent_meshes", icon='OUTLINER_OB_ARMATURE')
+1
View File
@@ -13,6 +13,7 @@ class AvatarToolKit_PT_OptimizationPanel(Panel):
bl_category: str = CATEGORY_NAME
bl_parent_id: str = AvatarToolKit_PT_AvatarToolkitPanel.bl_idname
bl_order: int = 1
bl_options = {'DEFAULT_CLOSED'}
def draw(self, context: Context) -> None:
"""Draws the optimization panel interface with material, mesh cleanup and join mesh tools"""
+1
View File
@@ -37,6 +37,7 @@ class AvatarToolKit_PT_SettingsPanel(Panel):
bl_category: str = CATEGORY_NAME
bl_parent_id: str = AvatarToolKit_PT_AvatarToolkitPanel.bl_idname
bl_order: int = 5
bl_options = {'DEFAULT_CLOSED'}
def draw(self, context: Context) -> None:
"""Draw the settings panel layout with language selection"""
+1
View File
@@ -13,6 +13,7 @@ class AvatarToolKit_PT_ToolsPanel(Panel):
bl_category: str = CATEGORY_NAME
bl_parent_id: str = AvatarToolKit_PT_AvatarToolkitPanel.bl_idname
bl_order: int = 2
bl_options = {'DEFAULT_CLOSED'}
def draw(self, context: Context) -> None:
"""Draw the tools panel interface"""
+60
View File
@@ -0,0 +1,60 @@
from bpy.types import Panel, Context, UILayout
from ..core.translations import t
from .main_panel import AvatarToolKit_PT_AvatarToolkitPanel, CATEGORY_NAME
class AvatarToolKit_PT_VisemesPanel(Panel):
"""Panel containing viseme creation and preview tools"""
bl_label: str = t("Visemes.panel_label")
bl_idname: str = "VIEW3D_PT_avatar_toolkit_visemes"
bl_space_type: str = 'VIEW_3D'
bl_region_type: str = 'UI'
bl_category: str = CATEGORY_NAME
bl_parent_id: str = AvatarToolKit_PT_AvatarToolkitPanel.bl_idname
bl_order: int = 4
bl_options = {'DEFAULT_CLOSED'}
def draw(self, context: Context) -> None:
"""Draw the visemes panel interface"""
layout: UILayout = self.layout
props = context.scene.avatar_toolkit
# Check for valid mesh with shape keys
if not context.active_object or context.active_object.type != 'MESH' or not context.active_object.data.shape_keys:
layout.label(text=t("Visemes.no_shapekeys"))
return
# Shape Key Selection Box
shape_box: UILayout = layout.box()
col: UILayout = shape_box.column(align=True)
col.label(text=t("Visemes.shape_selection"), icon='SHAPEKEY_DATA')
col.separator(factor=0.5)
# Shape key selection with valid data
shape_keys = context.active_object.data.shape_keys
col.prop_search(props, "mouth_a", shape_keys, "key_blocks", text=t("Visemes.mouth_a"))
col.prop_search(props, "mouth_o", shape_keys, "key_blocks", text=t("Visemes.mouth_o"))
col.prop_search(props, "mouth_ch", shape_keys, "key_blocks", text=t("Visemes.mouth_ch"))
# Shape intensity slider
col.separator()
col.prop(props, "shape_intensity", slider=True)
# Preview Box
preview_box: UILayout = layout.box()
col = preview_box.column(align=True)
col.label(text=t("Visemes.preview_label"), icon='HIDE_OFF')
col.separator(factor=0.5)
if props.viseme_preview_mode:
col.prop(props, "viseme_preview_selection", text="")
col.separator()
preview_text = t("Visemes.stop_preview") if props.viseme_preview_mode else t("Visemes.start_preview")
col.operator("avatar_toolkit.preview_visemes", text=preview_text, icon='HIDE_OFF')
# Create Box
create_box: UILayout = layout.box()
col = create_box.column(align=True)
col.label(text=t("Visemes.create_label"), icon='ADD')
col.separator(factor=0.5)
col.operator("avatar_toolkit.create_visemes", icon='ADD')