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

View File

@@ -0,0 +1,82 @@
# SPDX-License-Identifier: MIT OR GPL-3.0-or-later
import re
from dataclasses import dataclass
from pathlib import Path
from typing import Optional
@dataclass(frozen=True)
class BlenderManifest:
id: str
version: tuple[int, int, int]
blender_version_min: tuple[int, int, int]
blender_version_max: Optional[tuple[int, int, int]]
@classmethod
def default_blender_manifest_path(cls) -> Path:
return Path(__file__).parent.parent / "blender_manifest.toml"
@classmethod
def read_str(cls, blender_manifest: str, key: str) -> Optional[str]:
# When the version of Python used by the minimum supported version of Blender
# exceeds 3.11, it is rewritten in the tomli library.
lines = list(map(str.strip, blender_manifest.splitlines()))
pattern = key + r' = "([^"]+)"'
for line in lines:
match = re.fullmatch(pattern, line)
if not match:
continue
return match[1]
return None
@classmethod
def read_3_tuple_version(
cls, blender_manifest: str, key: str
) -> Optional[tuple[int, int, int]]:
# When the version of Python used by the minimum supported version of Blender
# exceeds 3.11, it is rewritten in the tomli library.
lines = list(map(str.strip, blender_manifest.splitlines()))
pattern = key + r' = "(\d+)\.(\d+)\.(\d+)"'
for line in lines:
match = re.fullmatch(pattern, line)
if not match:
continue
return (int(match[1]), int(match[2]), int(match[3]))
return None
@classmethod
def read(cls, blender_manifest: Optional[str] = None) -> "BlenderManifest":
if blender_manifest is None:
blender_manifest = cls.default_blender_manifest_path().read_text(
encoding="UTF-8"
)
addon_id = cls.read_str(blender_manifest, "id")
if addon_id is None:
message = "'id' was not found in blender manifest"
raise ValueError(message)
version = cls.read_3_tuple_version(blender_manifest, "version")
if version is None:
message = "'version' was not found in blender manifest"
raise ValueError(message)
blender_version_min = cls.read_3_tuple_version(
blender_manifest, "blender_version_min"
)
if blender_version_min is None:
message = "'blender_version_min' was not found in blender manifest"
raise ValueError(message)
return BlenderManifest(
id=addon_id,
version=version,
blender_version_min=blender_version_min,
blender_version_max=cls.read_3_tuple_version(
blender_manifest, "blender_version_max"
),
)