Progress System
- Added Progress system so the user knows something is being done when there use certain functions. Currently only Join Meshes, Viseme creation and combine materials use it. - Disbabled some translation debguing stuff to remove spam from the console.
This commit is contained in:
+18
-1
@@ -6,10 +6,11 @@ import time
|
|||||||
import webbrowser
|
import webbrowser
|
||||||
import typing
|
import typing
|
||||||
|
|
||||||
|
from ..core.register import register_wrap
|
||||||
from typing import List, Optional, Tuple
|
from typing import List, Optional, Tuple
|
||||||
from bpy.types import Object, ShapeKey, Mesh, Context, Material, PropertyGroup
|
from bpy.types import Object, ShapeKey, Mesh, Context, Material, PropertyGroup
|
||||||
from functools import lru_cache
|
from functools import lru_cache
|
||||||
from bpy.props import PointerProperty
|
from bpy.props import PointerProperty, IntProperty, StringProperty
|
||||||
from bpy.utils import register_class
|
from bpy.utils import register_class
|
||||||
|
|
||||||
|
|
||||||
@@ -245,3 +246,19 @@ def remove_default_objects():
|
|||||||
for obj in bpy.data.objects:
|
for obj in bpy.data.objects:
|
||||||
if obj.name in ["Camera", "Light", "Cube"]:
|
if obj.name in ["Camera", "Light", "Cube"]:
|
||||||
bpy.data.objects.remove(obj, do_unlink=True)
|
bpy.data.objects.remove(obj, do_unlink=True)
|
||||||
|
|
||||||
|
def init_progress(context, steps):
|
||||||
|
context.window_manager.progress_begin(0, 100)
|
||||||
|
context.scene.avatar_toolkit_progress_steps = steps
|
||||||
|
context.scene.avatar_toolkit_progress_current = 0
|
||||||
|
|
||||||
|
def update_progress(self, context, message):
|
||||||
|
context.scene.avatar_toolkit_progress_current += 1
|
||||||
|
progress = (context.scene.avatar_toolkit_progress_current / context.scene.avatar_toolkit_progress_steps) * 100
|
||||||
|
context.window_manager.progress_update(progress)
|
||||||
|
context.area.header_text_set(message)
|
||||||
|
self.report({'INFO'}, message)
|
||||||
|
|
||||||
|
def finish_progress(context):
|
||||||
|
context.window_manager.progress_end()
|
||||||
|
context.area.header_text_set(None)
|
||||||
|
|||||||
@@ -26,6 +26,9 @@ def register() -> None:
|
|||||||
|
|
||||||
bpy.types.Scene.avatar_toolkit_language_changed = bpy.props.BoolProperty(default=False)
|
bpy.types.Scene.avatar_toolkit_language_changed = bpy.props.BoolProperty(default=False)
|
||||||
|
|
||||||
|
bpy.types.Scene.avatar_toolkit_progress_steps = bpy.props.IntProperty(default=0)
|
||||||
|
bpy.types.Scene.avatar_toolkit_progress_current = bpy.props.IntProperty(default=0)
|
||||||
|
|
||||||
bpy.types.Scene.mouth_a = bpy.props.StringProperty(
|
bpy.types.Scene.mouth_a = bpy.props.StringProperty(
|
||||||
name=t("VisemePanel.mouth_a.label"),
|
name=t("VisemePanel.mouth_a.label"),
|
||||||
description=t("VisemePanel.mouth_a.desc")
|
description=t("VisemePanel.mouth_a.desc")
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import bpy
|
|||||||
import re
|
import re
|
||||||
from typing import List, Tuple, Optional, Set, Dict
|
from typing import List, Tuple, Optional, Set, Dict
|
||||||
from bpy.types import Material, Operator, Context, Object, NodeTree
|
from bpy.types import Material, Operator, Context, Object, NodeTree
|
||||||
from ..core.common import clean_material_names, get_selected_armature, is_valid_armature, get_all_meshes
|
from ..core.common import clean_material_names, get_selected_armature, is_valid_armature, get_all_meshes, init_progress, update_progress, finish_progress
|
||||||
from ..core.register import register_wrap
|
from ..core.register import register_wrap
|
||||||
from ..functions.translations import t
|
from ..functions.translations import t
|
||||||
|
|
||||||
@@ -78,11 +78,23 @@ class CombineMaterials(Operator):
|
|||||||
self.report({'WARNING'}, t("Optimization.no_meshes_found"))
|
self.report({'WARNING'}, t("Optimization.no_meshes_found"))
|
||||||
return {'CANCELLED'}
|
return {'CANCELLED'}
|
||||||
|
|
||||||
|
init_progress(context, 5) # 5 steps in total
|
||||||
|
|
||||||
|
update_progress(self, context, t("Optimization.consolidating_materials"))
|
||||||
self.consolidate_materials(meshes)
|
self.consolidate_materials(meshes)
|
||||||
|
|
||||||
|
update_progress(self, context, t("Optimization.cleaning_material_slots"))
|
||||||
self.clean_material_slots(meshes)
|
self.clean_material_slots(meshes)
|
||||||
|
|
||||||
|
update_progress(self, context, t("Optimization.cleaning_material_names"))
|
||||||
self.clean_material_names()
|
self.clean_material_names()
|
||||||
|
|
||||||
|
update_progress(self, context, t("Optimization.clearing_unused_data"))
|
||||||
self.clear_unused_data_blocks()
|
self.clear_unused_data_blocks()
|
||||||
|
|
||||||
|
update_progress(self, context, t("Optimization.finalizing"))
|
||||||
|
finish_progress(context)
|
||||||
|
|
||||||
return {'FINISHED'}
|
return {'FINISHED'}
|
||||||
|
|
||||||
def consolidate_materials(self, meshes: List[Object]) -> None:
|
def consolidate_materials(self, meshes: List[Object]) -> None:
|
||||||
@@ -123,3 +135,4 @@ class CombineMaterials(Operator):
|
|||||||
|
|
||||||
def clear_unused_data_blocks(self) -> None:
|
def clear_unused_data_blocks(self) -> None:
|
||||||
bpy.ops.outliner.orphans_purge(do_local_ids=True, do_linked_ids=True, do_recursive=True)
|
bpy.ops.outliner.orphans_purge(do_local_ids=True, do_linked_ids=True, do_recursive=True)
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import bpy
|
|||||||
from typing import List, Optional, Set
|
from typing import List, Optional, Set
|
||||||
from bpy.types import Operator, Context, Object
|
from bpy.types import Operator, Context, Object
|
||||||
from ..core.register import register_wrap
|
from ..core.register import register_wrap
|
||||||
from ..core.common import fix_uv_coordinates, get_selected_armature, is_valid_armature, select_current_armature, get_all_meshes
|
from ..core.common import fix_uv_coordinates, get_selected_armature, is_valid_armature, select_current_armature, get_all_meshes, init_progress, update_progress, finish_progress
|
||||||
from ..functions.translations import t
|
from ..functions.translations import t
|
||||||
|
|
||||||
@register_wrap
|
@register_wrap
|
||||||
@@ -37,22 +37,31 @@ class JoinAllMeshes(Operator):
|
|||||||
if not meshes:
|
if not meshes:
|
||||||
raise ValueError(t("Optimization.no_meshes_found"))
|
raise ValueError(t("Optimization.no_meshes_found"))
|
||||||
|
|
||||||
|
init_progress(context, 5) # 5 steps in total
|
||||||
|
|
||||||
|
update_progress(self, context, t("Optimization.selecting_meshes"))
|
||||||
for mesh in meshes:
|
for mesh in meshes:
|
||||||
mesh.select_set(True)
|
mesh.select_set(True)
|
||||||
|
|
||||||
if bpy.context.selected_objects:
|
if bpy.context.selected_objects:
|
||||||
bpy.context.view_layer.objects.active = bpy.context.selected_objects[0]
|
bpy.context.view_layer.objects.active = bpy.context.selected_objects[0]
|
||||||
|
|
||||||
|
update_progress(self, context, t("Optimization.joining_meshes"))
|
||||||
try:
|
try:
|
||||||
bpy.ops.object.join()
|
bpy.ops.object.join()
|
||||||
except RuntimeError as e:
|
except RuntimeError as e:
|
||||||
raise RuntimeError(f"{t('Optimization.join_operation_failed')}: {str(e)}")
|
raise RuntimeError(f"{t('Optimization.join_operation_failed')}: {str(e)}")
|
||||||
|
|
||||||
|
update_progress(self, context, t("Optimization.applying_transforms"))
|
||||||
try:
|
try:
|
||||||
bpy.ops.object.transform_apply(location=True, rotation=True, scale=True)
|
bpy.ops.object.transform_apply(location=True, rotation=True, scale=True)
|
||||||
except RuntimeError as e:
|
except RuntimeError as e:
|
||||||
raise RuntimeError(f"{t('Optimization.transform_apply_failed')}: {str(e)}")
|
raise RuntimeError(f"{t('Optimization.transform_apply_failed')}: {str(e)}")
|
||||||
|
|
||||||
|
update_progress(self, context, t("Optimization.fixing_uv_coordinates"))
|
||||||
fix_uv_coordinates(context)
|
fix_uv_coordinates(context)
|
||||||
|
|
||||||
|
update_progress(self, context, t("Optimization.finalizing"))
|
||||||
bpy.ops.object.mode_set(mode='OBJECT')
|
bpy.ops.object.mode_set(mode='OBJECT')
|
||||||
bpy.ops.object.select_all(action='DESELECT')
|
bpy.ops.object.select_all(action='DESELECT')
|
||||||
self.report({'INFO'}, t("Optimization.meshes_joined"))
|
self.report({'INFO'}, t("Optimization.meshes_joined"))
|
||||||
@@ -60,6 +69,7 @@ class JoinAllMeshes(Operator):
|
|||||||
raise ValueError(t("Optimization.no_mesh_selected"))
|
raise ValueError(t("Optimization.no_mesh_selected"))
|
||||||
|
|
||||||
context.view_layer.objects.active = armature
|
context.view_layer.objects.active = armature
|
||||||
|
finish_progress(context)
|
||||||
|
|
||||||
@register_wrap
|
@register_wrap
|
||||||
class JoinSelectedMeshes(Operator):
|
class JoinSelectedMeshes(Operator):
|
||||||
@@ -86,24 +96,32 @@ class JoinSelectedMeshes(Operator):
|
|||||||
if len(selected_objects) < 2:
|
if len(selected_objects) < 2:
|
||||||
raise ValueError(t("Optimization.select_at_least_two_meshes"))
|
raise ValueError(t("Optimization.select_at_least_two_meshes"))
|
||||||
|
|
||||||
|
init_progress(context, 5) # 5 steps in total
|
||||||
|
|
||||||
|
update_progress(self, context, t("Optimization.preparing_meshes"))
|
||||||
bpy.ops.object.mode_set(mode='OBJECT')
|
bpy.ops.object.mode_set(mode='OBJECT')
|
||||||
bpy.ops.object.select_all(action='DESELECT')
|
bpy.ops.object.select_all(action='DESELECT')
|
||||||
|
|
||||||
|
update_progress(self, context, t("Optimization.selecting_meshes"))
|
||||||
for obj in selected_objects:
|
for obj in selected_objects:
|
||||||
obj.select_set(True)
|
obj.select_set(True)
|
||||||
|
|
||||||
if bpy.context.selected_objects:
|
if bpy.context.selected_objects:
|
||||||
bpy.context.view_layer.objects.active = bpy.context.selected_objects[0]
|
bpy.context.view_layer.objects.active = bpy.context.selected_objects[0]
|
||||||
|
|
||||||
|
update_progress(self, context, t("Optimization.joining_meshes"))
|
||||||
try:
|
try:
|
||||||
bpy.ops.object.join()
|
bpy.ops.object.join()
|
||||||
except RuntimeError as e:
|
except RuntimeError as e:
|
||||||
raise RuntimeError(f"{t('Optimization.join_operation_failed')}: {str(e)}")
|
raise RuntimeError(f"{t('Optimization.join_operation_failed')}: {str(e)}")
|
||||||
|
|
||||||
|
update_progress(self, context, t("Optimization.applying_transforms"))
|
||||||
try:
|
try:
|
||||||
bpy.ops.object.transform_apply(location=True, rotation=True, scale=True)
|
bpy.ops.object.transform_apply(location=True, rotation=True, scale=True)
|
||||||
except RuntimeError as e:
|
except RuntimeError as e:
|
||||||
raise RuntimeError(f"{t('Optimization.transform_apply_failed')}: {str(e)}")
|
raise RuntimeError(f"{t('Optimization.transform_apply_failed')}: {str(e)}")
|
||||||
|
|
||||||
|
update_progress(self, context, t("Optimization.fixing_uv_coordinates"))
|
||||||
fix_uv_coordinates(context)
|
fix_uv_coordinates(context)
|
||||||
bpy.ops.object.mode_set(mode='OBJECT')
|
bpy.ops.object.mode_set(mode='OBJECT')
|
||||||
bpy.ops.object.select_all(action='DESELECT')
|
bpy.ops.object.select_all(action='DESELECT')
|
||||||
@@ -111,3 +129,4 @@ class JoinSelectedMeshes(Operator):
|
|||||||
else:
|
else:
|
||||||
raise ValueError(t("Optimization.no_mesh_selected"))
|
raise ValueError(t("Optimization.no_mesh_selected"))
|
||||||
|
|
||||||
|
finish_progress(context)
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ def load_translations() -> bool:
|
|||||||
languages.append(lang)
|
languages.append(lang)
|
||||||
|
|
||||||
language_index = get_preference("language", 0)
|
language_index = get_preference("language", 0)
|
||||||
print(f"Loading translations for language index: {language_index}") # Debug print
|
# print(f"Loading translations for language index: {language_index}") # Debug print
|
||||||
|
|
||||||
if language_index == 0: # "auto"
|
if language_index == 0: # "auto"
|
||||||
language = bpy.context.preferences.view.language
|
language = bpy.context.preferences.view.language
|
||||||
@@ -40,27 +40,27 @@ def load_translations() -> bool:
|
|||||||
except IndexError:
|
except IndexError:
|
||||||
language = bpy.context.preferences.view.language
|
language = bpy.context.preferences.view.language
|
||||||
|
|
||||||
print(f"Selected language: {language}") # Debug print
|
# print(f"Selected language: {language}") # Debug print
|
||||||
|
|
||||||
translation_file: str = os.path.join(translations_dir, language + ".json")
|
translation_file: str = os.path.join(translations_dir, language + ".json")
|
||||||
if os.path.exists(translation_file):
|
if os.path.exists(translation_file):
|
||||||
with open(translation_file, 'r', encoding='utf-8') as file:
|
with open(translation_file, 'r', encoding='utf-8') as file:
|
||||||
dictionary = json.load(file)["messages"]
|
dictionary = json.load(file)["messages"]
|
||||||
print(f"Loaded translations: {dictionary}") # Debug print
|
# print(f"Loaded translations: {dictionary}") # Debug print
|
||||||
else:
|
else:
|
||||||
custom_language: str = language.split("_")[0]
|
custom_language: str = language.split("_")[0]
|
||||||
custom_translation_file: str = os.path.join(translations_dir, custom_language + ".json")
|
custom_translation_file: str = os.path.join(translations_dir, custom_language + ".json")
|
||||||
if os.path.exists(custom_translation_file):
|
if os.path.exists(custom_translation_file):
|
||||||
with open(custom_translation_file, 'r', encoding='utf-8') as file:
|
with open(custom_translation_file, 'r', encoding='utf-8') as file:
|
||||||
dictionary = json.load(file)["messages"]
|
dictionary = json.load(file)["messages"]
|
||||||
print(f"Loaded custom translations: {dictionary}") # Debug print
|
# print(f"Loaded custom translations: {dictionary}") # Debug print
|
||||||
else:
|
else:
|
||||||
print(f"Translation file not found for language: {language}")
|
print(f"Translation file not found for language: {language}")
|
||||||
default_file: str = os.path.join(translations_dir, "en_US.json")
|
default_file: str = os.path.join(translations_dir, "en_US.json")
|
||||||
if os.path.exists(default_file):
|
if os.path.exists(default_file):
|
||||||
with open(default_file, 'r', encoding='utf-8') as file:
|
with open(default_file, 'r', encoding='utf-8') as file:
|
||||||
dictionary = json.load(file)["messages"]
|
dictionary = json.load(file)["messages"]
|
||||||
print(f"Loaded default translations: {dictionary}") # Debug print
|
# print(f"Loaded default translations: {dictionary}") # Debug print
|
||||||
else:
|
else:
|
||||||
print("Default translation file 'en_US.json' not found.")
|
print("Default translation file 'en_US.json' not found.")
|
||||||
|
|
||||||
@@ -72,7 +72,7 @@ def t(phrase: str, default: str = None) -> str:
|
|||||||
if verbose:
|
if verbose:
|
||||||
print(f'Warning: Unknown phrase: {phrase}')
|
print(f'Warning: Unknown phrase: {phrase}')
|
||||||
return default if default is not None else phrase
|
return default if default is not None else phrase
|
||||||
print(f"Translating '{phrase}' to '{output}'") # Debug print
|
# print(f"Translating '{phrase}' to '{output}'") # Debug print
|
||||||
return output
|
return output
|
||||||
|
|
||||||
def get_language_display_name(lang: str) -> str:
|
def get_language_display_name(lang: str) -> str:
|
||||||
@@ -93,5 +93,5 @@ def update_language(self, context):
|
|||||||
bpy.ops.avatar_toolkit.translation_restart_popup('INVOKE_DEFAULT')
|
bpy.ops.avatar_toolkit.translation_restart_popup('INVOKE_DEFAULT')
|
||||||
|
|
||||||
# Initial load of translations
|
# Initial load of translations
|
||||||
print("Performing initial load of translations") # Debug print
|
# print("Performing initial load of translations") # Debug print
|
||||||
load_translations()
|
load_translations()
|
||||||
|
|||||||
+20
-23
@@ -3,7 +3,7 @@ from ..core import common
|
|||||||
from ..core.register import register_wrap
|
from ..core.register import register_wrap
|
||||||
from ..functions.translations import t
|
from ..functions.translations import t
|
||||||
from typing import List, Tuple
|
from typing import List, Tuple
|
||||||
from ..core.common import get_selected_armature, is_valid_armature, get_all_meshes
|
from ..core.common import get_selected_armature, is_valid_armature, get_all_meshes, init_progress, update_progress, finish_progress
|
||||||
|
|
||||||
@register_wrap
|
@register_wrap
|
||||||
class AutoVisemeButton(bpy.types.Operator):
|
class AutoVisemeButton(bpy.types.Operator):
|
||||||
@@ -18,26 +18,32 @@ class AutoVisemeButton(bpy.types.Operator):
|
|||||||
return armature is not None and is_valid_armature(armature) and get_all_meshes(context)
|
return armature is not None and is_valid_armature(armature) and get_all_meshes(context)
|
||||||
|
|
||||||
def execute(self, context: bpy.types.Context) -> set:
|
def execute(self, context: bpy.types.Context) -> set:
|
||||||
print("Starting viseme creation...")
|
try:
|
||||||
mesh = bpy.data.objects.get(context.scene.selected_mesh)
|
self.create_visemes(context)
|
||||||
if not mesh or not common.has_shapekeys(mesh):
|
return {'FINISHED'}
|
||||||
self.report({'ERROR'}, t('AutoVisemeButton.error.noShapekeys'))
|
except Exception as e:
|
||||||
|
self.report({'ERROR'}, str(e))
|
||||||
return {'CANCELLED'}
|
return {'CANCELLED'}
|
||||||
|
|
||||||
# Remove existing VRC shape keys
|
def create_visemes(self, context: bpy.types.Context) -> None:
|
||||||
|
init_progress(context, 5) # 5 main steps
|
||||||
|
|
||||||
|
update_progress(self, context, t("VisemePanel.start_viseme_creation"))
|
||||||
|
mesh = bpy.data.objects.get(context.scene.selected_mesh)
|
||||||
|
if not mesh or not common.has_shapekeys(mesh):
|
||||||
|
raise ValueError(t('AutoVisemeButton.error.noShapekeys'))
|
||||||
|
|
||||||
|
update_progress(self, context, t("VisemePanel.removing_existing_visemes"))
|
||||||
self.remove_existing_vrc_shapekeys(mesh)
|
self.remove_existing_vrc_shapekeys(mesh)
|
||||||
|
|
||||||
shape_a = context.scene.mouth_a
|
shape_a = context.scene.mouth_a
|
||||||
shape_o = context.scene.mouth_o
|
shape_o = context.scene.mouth_o
|
||||||
shape_ch = context.scene.mouth_ch
|
shape_ch = context.scene.mouth_ch
|
||||||
|
|
||||||
print(f"Selected shapes: A={shape_a}, O={shape_o}, CH={shape_ch}")
|
|
||||||
|
|
||||||
if shape_a == "Basis" or shape_o == "Basis" or shape_ch == "Basis":
|
if shape_a == "Basis" or shape_o == "Basis" or shape_ch == "Basis":
|
||||||
self.report({'ERROR'}, t('AutoVisemeButton.error.selectShapekeys'))
|
raise ValueError(t('AutoVisemeButton.error.selectShapekeys'))
|
||||||
return {'CANCELLED'}
|
|
||||||
|
|
||||||
# Create visemes
|
update_progress(self, context, t("VisemePanel.creating_visemes"))
|
||||||
visemes: List[Tuple[str, List[Tuple[str, float]]]] = [
|
visemes: List[Tuple[str, List[Tuple[str, float]]]] = [
|
||||||
('vrc.v_aa', [(shape_a, 0.9998)]),
|
('vrc.v_aa', [(shape_a, 0.9998)]),
|
||||||
('vrc.v_ch', [(shape_ch, 0.9996)]),
|
('vrc.v_ch', [(shape_ch, 0.9996)]),
|
||||||
@@ -57,38 +63,29 @@ class AutoVisemeButton(bpy.types.Operator):
|
|||||||
]
|
]
|
||||||
|
|
||||||
for viseme_name, shape_mix in visemes:
|
for viseme_name, shape_mix in visemes:
|
||||||
print(f"Creating viseme: {viseme_name}")
|
|
||||||
self.create_viseme(mesh, viseme_name, shape_mix, context.scene.shape_intensity)
|
self.create_viseme(mesh, viseme_name, shape_mix, context.scene.shape_intensity)
|
||||||
|
|
||||||
print("Sorting shape keys...")
|
update_progress(self, context, t("VisemePanel.sorting_shapekeys"))
|
||||||
common.sort_shape_keys(mesh)
|
common.sort_shape_keys(mesh)
|
||||||
|
|
||||||
self.report({'INFO'}, t('AutoVisemeButton.success'))
|
update_progress(self, context, t("VisemePanel.viseme_creation_completed"))
|
||||||
return {'FINISHED'}
|
finish_progress(context)
|
||||||
|
|
||||||
def create_viseme(self, mesh: bpy.types.Object, viseme_name: str, shape_mix: List[Tuple[str, float]], intensity: float) -> None:
|
def create_viseme(self, mesh: bpy.types.Object, viseme_name: str, shape_mix: List[Tuple[str, float]], intensity: float) -> None:
|
||||||
print(f" Creating viseme: {viseme_name}")
|
|
||||||
shape_keys = mesh.data.shape_keys.key_blocks
|
shape_keys = mesh.data.shape_keys.key_blocks
|
||||||
|
|
||||||
# Remove existing viseme if it exists
|
|
||||||
if viseme_name in shape_keys:
|
if viseme_name in shape_keys:
|
||||||
print(f" Removing existing viseme: {viseme_name}")
|
|
||||||
mesh.shape_key_remove(shape_keys[viseme_name])
|
mesh.shape_key_remove(shape_keys[viseme_name])
|
||||||
|
|
||||||
# Create new viseme
|
|
||||||
new_key = mesh.shape_key_add(name=viseme_name, from_mix=False)
|
new_key = mesh.shape_key_add(name=viseme_name, from_mix=False)
|
||||||
new_key.value = 0.0
|
new_key.value = 0.0
|
||||||
|
|
||||||
# Mix shapes
|
|
||||||
for shape_name, value in shape_mix:
|
for shape_name, value in shape_mix:
|
||||||
if shape_name in shape_keys:
|
if shape_name in shape_keys:
|
||||||
source_shape = shape_keys[shape_name]
|
source_shape = shape_keys[shape_name]
|
||||||
print(f" Mixing shape: {shape_name} with value: {value * intensity}")
|
|
||||||
for i, vert in enumerate(new_key.data):
|
for i, vert in enumerate(new_key.data):
|
||||||
vert.co += (source_shape.data[i].co - shape_keys['Basis'].data[i].co) * value * intensity
|
vert.co += (source_shape.data[i].co - shape_keys['Basis'].data[i].co) * value * intensity
|
||||||
|
|
||||||
print(f" Viseme {viseme_name} created successfully.")
|
|
||||||
|
|
||||||
def remove_existing_vrc_shapekeys(self, mesh: bpy.types.Object) -> None:
|
def remove_existing_vrc_shapekeys(self, mesh: bpy.types.Object) -> None:
|
||||||
vrc_prefixes = ['vrc.v_', 'vrc.blink_', 'vrc.lowerlid_']
|
vrc_prefixes = ['vrc.v_', 'vrc.blink_', 'vrc.lowerlid_']
|
||||||
shape_keys = mesh.data.shape_keys.key_blocks
|
shape_keys = mesh.data.shape_keys.key_blocks
|
||||||
|
|||||||
@@ -56,6 +56,16 @@
|
|||||||
"Optimization.join_error": "Error during mesh joining",
|
"Optimization.join_error": "Error during mesh joining",
|
||||||
"Optimization.join_operation_failed": "Join operation failed",
|
"Optimization.join_operation_failed": "Join operation failed",
|
||||||
"Optimization.transform_apply_failed": "Transform apply failed",
|
"Optimization.transform_apply_failed": "Transform apply failed",
|
||||||
|
"Optimization.selecting_meshes": "Selecting meshes...",
|
||||||
|
"Optimization.joining_meshes": "Joining meshes...",
|
||||||
|
"Optimization.applying_transforms": "Applying transforms...",
|
||||||
|
"Optimization.fixing_uv_coordinates": "Fixing UV coordinates...",
|
||||||
|
"Optimization.finalizing": "Finalizing...",
|
||||||
|
"Optimization.preparing_meshes": "Preparing meshes...",
|
||||||
|
"Optimization.consolidating_materials": "Consolidating materials...",
|
||||||
|
"Optimization.cleaning_material_slots": "Cleaning material slots...",
|
||||||
|
"Optimization.cleaning_material_names": "Cleaning material names...",
|
||||||
|
"Optimization.clearing_unused_data": "Clearing unused data...",
|
||||||
"Tools.select_armature": "Please select an armature",
|
"Tools.select_armature": "Please select an armature",
|
||||||
"Tools.label": "Tools",
|
"Tools.label": "Tools",
|
||||||
"Tools.tools_title.label": "Tools:",
|
"Tools.tools_title.label": "Tools:",
|
||||||
@@ -102,6 +112,8 @@
|
|||||||
"VisemePanel.removing_existing_viseme": "Removing existing viseme: {viseme_name}",
|
"VisemePanel.removing_existing_viseme": "Removing existing viseme: {viseme_name}",
|
||||||
"VisemePanel.mixing_shape": "Mixing shape: {shape_name} with value: {value}",
|
"VisemePanel.mixing_shape": "Mixing shape: {shape_name} with value: {value}",
|
||||||
"VisemePanel.viseme_created_successfully": "Viseme {viseme_name} created successfully",
|
"VisemePanel.viseme_created_successfully": "Viseme {viseme_name} created successfully",
|
||||||
|
"VisemePanel.removing_existing_visemes": "Removing existing visemes...",
|
||||||
|
"VisemePanel.creating_visemes": "Creating visemes...",
|
||||||
"AutoVisemeButton.label": "Create Visemes",
|
"AutoVisemeButton.label": "Create Visemes",
|
||||||
"AutoVisemeButton.desc": "Create visemes automatically, based on shape keys",
|
"AutoVisemeButton.desc": "Create visemes automatically, based on shape keys",
|
||||||
"AutoVisemeButton.error.noShapekeys": "No shape keys found",
|
"AutoVisemeButton.error.noShapekeys": "No shape keys found",
|
||||||
|
|||||||
Reference in New Issue
Block a user