feat: Add VRM Blender addon with complete import/export functionality

- Add core VRM addon infrastructure with manifest and registration
- Add common utilities module with file system, logging, and conversion helpers
- Add human bone mapper with support for multiple rigging standards (Mixamo, MMD, Unreal, Rigify, etc.)
- Add VRM 0.x and 1.x format support with property groups and handlers
- Add editor UI panels for VRM metadata, spring bones, and MToon materials
- Add exporter with glTF2 extension support for VRM format serialization
- Add importer with scene reconstruction and armature generation
- Add MToon shader support with auto-setup and material migration
- Add spring bone physics simulation with constraint handling
- Add node constraint editor for advanced rigging control
- Add comprehensive validation and error handling with user dialogs
- Add scene watcher for real-time property synchronization
- Add workspace management and preference system
- Include Python cache files and Blender manifest configuration
- This is the initial commit establishing the complete VRM addon ecosystem for Blender
This commit is contained in:
2026-01-01 14:21:56 +08:00
commit 091ad6a49a
243 changed files with 60636 additions and 0 deletions

58
common/logger.py Normal file
View File

@@ -0,0 +1,58 @@
# SPDX-License-Identifier: MIT OR GPL-3.0-or-later
import logging
import sys
from collections.abc import Mapping
from os import environ
from types import TracebackType
from typing import TYPE_CHECKING, Optional, Union
import bpy
# https://github.com/python/typeshed/issues/7855
if TYPE_CHECKING or sys.version_info >= (3, 11):
LoggerAdapter = logging.LoggerAdapter[logging.Logger]
else:
LoggerAdapter = logging.LoggerAdapter
class VrmAddonLoggerAdapter(LoggerAdapter):
def log(
self,
level: int,
msg: object,
*args: object,
exc_info: Union[
None,
bool,
Union[
tuple[type[BaseException], BaseException, Optional[TracebackType]],
tuple[None, None, None],
],
BaseException,
] = None,
stack_info: bool = False,
stacklevel: int = 1,
extra: Optional[Mapping[str, object]] = None,
**kwargs: object,
) -> None:
level_name = logging.getLevelName(level)
super().log(
level,
f"[VRM Add-on:{level_name}] {msg}",
*args,
exc_info=exc_info,
stack_info=stack_info,
stacklevel=stacklevel,
extra=extra,
**kwargs,
)
# https://docs.python.org/3.7/library/logging.html#logging.getLogger
def get_logger(name: str) -> LoggerAdapter:
logger = logging.getLogger(name)
if bpy.app.debug or environ.get("BLENDER_VRM_LOGGING_LEVEL_DEBUG") == "yes":
logger.setLevel(min(logging.DEBUG, logger.getEffectiveLevel()))
else:
logger.setLevel(max(logging.INFO, logger.getEffectiveLevel()))
return VrmAddonLoggerAdapter(logger, {})