OpenFitterで使用されている主要な技術とアルゴリズムについて説明します。
OpenFitterは、3Dアバター間での衣装フィッティングを実現するために、複数の技術を組み合わせています。Unity Editor拡張としてのフロントエンドと、Blenderをバックエンドとして使用する処理エンジンで構成されています。
コアフィッティングアルゴリズムは RBF(Radial Basis Function)変形 を使用しています。
RBFは、限られた制御点から滑らかな変形を生成する数学的手法です。以下のような特徴があります:
- 局所的な影響: 各制御点は周囲の領域に主に影響を与えます
- 滑らかな補間: 制御点間の変形が自然で滑らかです
- 非線形変形: 複雑な体型の違いにも対応できます
- 制御点の設定: ソースとターゲットのボーン位置を制御点として使用
- RBF計算: ソースからターゲットへの変形を計算
- メッシュ変形: 衣装メッシュの各頂点にRBF変形を適用
アバター間でボーンの姿勢(ポーズ)を転送します。
- ボーンマッピング: ソースとターゲットのボーン構造を対応付け
- ポーズ抽出: ソースアバターのボーンポーズを抽出
- ポーズ適用: ターゲットアバターにポーズを適用
- ウェイト転送: スキニングウェイトを適切に転送
フィッティング後もメッシュの基本構造を維持します:
- 頂点順序: 元の頂点順序を保持
- ポリゴン構造: ポリゴンの接続関係を維持
- UV座標: テクスチャ座標を保持
- マテリアル: マテリアル割り当てを維持
OpenFitterはBlenderを3D処理エンジンとして使用しています:
- 強力な3D処理: Blenderの成熟した3D処理機能を活用
- Pythonスクリプティング: 柔軟な自動化が可能
- GPL-3コードの互換性: open-fitter-coreのコードをそのまま使用可能
- オープンソース: 無料で再配布可能
ユーザーの既存環境に影響を与えないよう、ポータブル版のBlenderを使用:
- 独立したインストール: システムのBlenderと干渉しない
- 自動ダウンロード: 初回セットアップ時に自動取得
- バージョン管理: 特定のバージョンを使用して互換性を保証
Unity(C#)とBlender(Python)間の橋渡しを行います:
メインのラッパースクリプト:
# コマンドライン引数からパラメータを受け取る
# open-fitter-coreのフィッティング関数を呼び出す
# 進捗情報を標準出力に出力
# 結果をファイルに保存アドオンのインストール状態を確認:
# Blenderアドオンが正しくインストールされているか確認
# バージョン情報を取得
# 結果をJSON形式で出力アドオンの依存関係をインストール:
# pipを使用して必要なPythonパッケージをインストール
# Blenderの内蔵Python環境にインストール
# インストール結果を報告UnityからBlenderをコマンドラインで起動:
blender.exe --background --python openfitter_wrapper.py -- [arguments]--background: UIなしのバックグラウンドモード--python: 実行するPythonスクリプト--: 以降の引数をスクリプトに渡す
Blenderバックエンド(openfitter_wrapper.pyを介したコアスクリプト)が受け取る主要な引数は以下の通りです。
| 引数 | 形式 | 必須 | 説明 |
|---|---|---|---|
--input |
パス | YES | 入力となる衣装FBXの絶対パス。 |
--output |
パス | YES | 出力先FBXの絶対パス。 |
--base |
パス | YES | 基準となる .blend ファイルのパス。 |
--base-fbx |
パスリスト | YES | ベースキャラクターのFBXパス。複数ある場合は ; で区切ります。 |
--config |
パスリスト | YES | 設定JSONのパス。複数ある場合は ; で区切ります。 |
--init-pose |
パス | YES | 初期ポーズ情報のJSONパス。 |
--hips-position |
文字列 | NO | Hipsボーンの位置指定。 |
--blend-shapes |
文字列リスト | NO | 適用するブレンドシェイプ名のリスト(; 区切り)。 |
--blend-shape-values |
数値リスト | NO | 各ブレンドシェイプの適用値(; 区切り)。 |
--blend-shape-mappings |
文字列リスト | NO | ブレンドシェイプのマッピング定義。 |
--target-meshes |
文字列リスト | NO | 処理対象とするメッシュ名のリスト。 |
--mesh-renderers |
文字列リスト | NO | メッシュレンダラーの対応設定。 |
--name-conv |
文字列リスト | NO | 名称変換ルールのリスト。 |
--preserve-bone-names |
フラグ | NO | ボーン名を維持するかどうかの指定。 |
--no-subdivision |
フラグ | NO | メッシュの自動細分化を無効にします。 |
--no-triangle |
フラグ | NO | 三角面化を無効にします。 |
モダンなUI開発フレームワークを使用:
XMLベースのレイアウト記述:
<ui:UXML>
<ui:VisualElement class="step-container">
<ui:Label text="Source Selection" class="step-title"/>
<ui:ObjectField name="source-field" type="UnityEngine.GameObject"/>
</ui:VisualElement>
</ui:UXML>CSSライクなスタイリング:
.step-container {
padding: 10px;
margin: 5px;
}
.step-title {
font-size: 16px;
-unity-font-style: bold;
}C#からUIを操作:
var sourceField = rootElement.Q<ObjectField>("source-field");
sourceField.RegisterValueChangedCallback(evt => {
// 値変更時の処理
});長時間実行される操作には非同期処理を使用:
public async Task<bool> ExecuteFittingAsync()
{
await Task.Run(() => {
// Blenderプロセスの実行
});
return true;
}Blenderからの出力をパースして進捗を表示:
public class FittingProgressParser
{
public void ParseLine(string line)
{
// "PROGRESS: 50%" のような出力をパース
// 進捗イベントを発火
}
}入出力に使用する3Dモデルフォーマット:
- 互換性: 多くの3Dツールでサポート
- 完全な情報: メッシュ、ボーン、アニメーション、マテリアルを含む
- Unity統合: Unityのネイティブサポート
フィッティング設定の保存:
{
"sourceAvatar": "Assets/Avatars/Source.fbx",
"targetAvatar": "Assets/Avatars/Target.fbx",
"blendShapes": [
{"name": "vrc.blink_left", "preserve": true},
{"name": "vrc.blink_right", "preserve": true}
]
}MochiFitterのデータフォーマットに準拠:
- 設定ファイル: 同じJSON構造を使用
- 出力形式: 互換性のあるFBX出力
- ブレンドシェイプ命名: VRChat標準に準拠
複数のタスクを並列実行:
var tasks = new List<Task<SetupResult>>
{
downloadBlenderTask,
downloadCoreTask,
downloadAddonTask
};
await Task.WhenAll(tasks);ダウンロードしたファイルをキャッシュ:
- ローカルキャッシュ:
BlenderTools/ディレクトリに保存 - バージョンチェック: ファイルが最新か確認
- 再利用: 既にダウンロード済みの場合はスキップ
大きなメッシュデータの効率的な処理:
- ストリーミング: ファイルをストリーミングで読み込み
- 早期解放: 不要になったデータは即座に解放
- プロセス分離: Blenderを別プロセスで実行してUnityのメモリ使用を抑制
Blenderプロセスを制限:
- 別プロセス: Unityとは独立したプロセスで実行
- 作業ディレクトリ制限: 特定のディレクトリ内でのみ動作
- タイムアウト: 長時間実行をタイムアウトで制限
ユーザー入力の検証:
public bool ValidateSourceAvatar(GameObject avatar)
{
if (avatar == null) return false;
if (!HasValidMesh(avatar)) return false;
if (!HasValidArmature(avatar)) return false;
return true;
}多言語サポート:
public static class I18n
{
public static string Get(string key)
{
// 現在の言語設定に基づいて文字列を取得
return translations[currentLanguage][key];
}
}- 日本語
- 英語
ユニットテストとインテグレーションテスト:
[Test]
public void TestSourceSelection()
{
var presenter = new SourceSelectionStepPresenter(mockView, state);
presenter.OnSourceSelected(testAvatar);
Assert.AreEqual(testAvatar, state.Config.SourceAvatar);
}テスト用のモック実装:
public class MockWizardView : IWizardView
{
public bool NextButtonWasCalled { get; private set; }
public void ShowNextButton()
{
NextButtonWasCalled = true;
}
}Node.jsとTypeScriptでビルドツールを作成:
// create-unitypackage.ts
import * as fs from 'fs';
import * as path from 'path';
async function createUnityPackage() {
// Unityパッケージを作成する処理
}ドキュメントサイトの生成:
npm run docs:build
# docs/.vitepress/dist/にビルド結果が生成されるOpenFitterは以下の技術を組み合わせて実現されています:
- RBF変形: 滑らかで自然な衣装フィッティング
- Blender統合: 強力な3D処理エンジン
- Unity Editor拡張: ユーザーフレンドリーなインターフェース
- 非同期処理: レスポンシブなユーザー体験
- モジュラー設計: 保守しやすく拡張可能な構造
これらの技術により、高品質な自動衣装フィッティングを実現しています。
This document explains the key technologies and algorithms used in OpenFitter.
OpenFitter combines multiple technologies to achieve clothing fitting between 3D avatars. It consists of a frontend as a Unity Editor extension and a processing engine using Blender as a backend.
The core fitting algorithm uses RBF (Radial Basis Function) deformation.
RBF is a mathematical technique that generates smooth deformation from limited control points. It has the following characteristics:
- Local Influence: Each control point primarily affects its surrounding area
- Smooth Interpolation: Deformation between control points is natural and smooth
- Nonlinear Deformation: Can handle complex body shape differences
- Control Point Setup: Use bone positions of source and target as control points
- RBF Calculation: Calculate deformation from source to target
- Mesh Deformation: Apply RBF deformation to each vertex of clothing mesh
Transfers bone pose between avatars.
- Bone Mapping: Map bone structures between source and target
- Pose Extraction: Extract bone pose from source avatar
- Pose Application: Apply pose to target avatar
- Weight Transfer: Appropriately transfer skinning weights
Maintains basic mesh structure after fitting:
- Vertex Order: Preserves original vertex order
- Polygon Structure: Maintains polygon connectivity
- UV Coordinates: Preserves texture coordinates
- Materials: Maintains material assignments
OpenFitter uses Blender as its 3D processing engine:
- Powerful 3D Processing: Leverages Blender's mature 3D processing capabilities
- Python Scripting: Enables flexible automation
- GPL-3 Code Compatibility: Can use open-fitter-core code directly
- Open Source: Free and redistributable
Uses portable version of Blender to avoid affecting user's existing environment:
- Independent Installation: Doesn't interfere with system Blender
- Automatic Download: Automatically retrieved during initial setup
- Version Management: Uses specific version to ensure compatibility
Bridges between Unity (C#) and Blender (Python):
Main wrapper script:
# Receive parameters from command line arguments
# Call fitting function of open-fitter-core
# Output progress information to stdout
# Save results to fileCheck add-on installation status:
# Check if Blender add-on is correctly installed
# Get version information
# Output results in JSON formatInstall add-on dependencies:
# Install required Python packages using pip
# Install into Blender's built-in Python environment
# Report installation resultsLaunch Blender from Unity via command line:
blender.exe --background --python openfitter_wrapper.py -- [arguments]--background: Background mode without UI--python: Python script to execute--: Pass subsequent arguments to script
The primary arguments accepted by the Blender backend (the core script via openfitter_wrapper.py) are as follows:
| Argument | Format | Required | Description |
|---|---|---|---|
--input |
Path | YES | Absolute path to the input clothing FBX. |
--output |
Path | YES | Absolute path to the output FBX. |
--base |
Path | YES | Path to the base .blend file. |
--base-fbx |
Path List | YES | Path to the base character FBX. Semicolon-separated if multiple. |
--config |
Path List | YES | Path to the config JSON. Semicolon-separated if multiple. |
--init-pose |
Path | YES | Path to the initial pose JSON. |
--hips-position |
String | NO | Specifies the Hips bone position. |
--blend-shapes |
String List | NO | List of blend shape names to apply (semicolon-separated). |
--blend-shape-values |
Value List | NO | Application values for each blend shape (semicolon-separated). |
--blend-shape-mappings |
String List | NO | Blend shape mapping definitions. |
--target-meshes |
String List | NO | List of mesh names to be processed. |
--mesh-renderers |
String List | NO | Mesh renderer correspondence settings. |
--name-conv |
String List | NO | List of name conversion rules. |
--preserve-bone-names |
Flag | NO | Specifies whether to preserve bone names. |
--no-subdivision |
Flag | NO | Disables automatic mesh subdivision. |
--no-triangle |
Flag | NO | Disables triangulation. |
Uses modern UI development framework:
XML-based layout description:
<ui:UXML>
<ui:VisualElement class="step-container">
<ui:Label text="Source Selection" class="step-title"/>
<ui:ObjectField name="source-field" type="UnityEngine.GameObject"/>
</ui:VisualElement>
</ui:UXML>CSS-like styling:
.step-container {
padding: 10px;
margin: 5px;
}
.step-title {
font-size: 16px;
-unity-font-style: bold;
}Manipulate UI from C#:
var sourceField = rootElement.Q<ObjectField>("source-field");
sourceField.RegisterValueChangedCallback(evt => {
// Handle value change
});Uses asynchronous processing for long-running operations:
public async Task<bool> ExecuteFittingAsync()
{
await Task.Run(() => {
// Execute Blender process
});
return true;
}Parse output from Blender to display progress:
public class FittingProgressParser
{
public void ParseLine(string line)
{
// Parse output like "PROGRESS: 50%"
// Fire progress event
}
}3D model format used for input/output:
- Compatibility: Supported by many 3D tools
- Complete Information: Includes mesh, bones, animations, materials
- Unity Integration: Native Unity support
Save fitting configuration:
{
"sourceAvatar": "Assets/Avatars/Source.fbx",
"targetAvatar": "Assets/Avatars/Target.fbx",
"blendShapes": [
{"name": "vrc.blink_left", "preserve": true},
{"name": "vrc.blink_right", "preserve": true}
]
}Complies with MochiFitter data format:
- Configuration Files: Uses same JSON structure
- Output Format: Compatible FBX output
- Blendshape Naming: Complies with VRChat standards
Execute multiple tasks in parallel:
var tasks = new List<Task<SetupResult>>
{
downloadBlenderTask,
downloadCoreTask,
downloadAddonTask
};
await Task.WhenAll(tasks);Cache downloaded files:
- Local Cache: Saved in
BlenderTools/directory - Version Check: Verify if files are up-to-date
- Reuse: Skip if already downloaded
Efficient processing of large mesh data:
- Streaming: Stream file loading
- Early Release: Immediately release unnecessary data
- Process Separation: Run Blender in separate process to reduce Unity memory usage
Restrict Blender process:
- Separate Process: Runs independently from Unity
- Working Directory Restriction: Operates only within specific directory
- Timeout: Limit long-running execution with timeout
Validate user input:
public bool ValidateSourceAvatar(GameObject avatar)
{
if (avatar == null) return false;
if (!HasValidMesh(avatar)) return false;
if (!HasValidArmature(avatar)) return false;
return true;
}Multi-language support:
public static class I18n
{
public static string Get(string key)
{
// Get string based on current language setting
return translations[currentLanguage][key];
}
}- Japanese
- English
Unit tests and integration tests:
[Test]
public void TestSourceSelection()
{
var presenter = new SourceSelectionStepPresenter(mockView, state);
presenter.OnSourceSelected(testAvatar);
Assert.AreEqual(testAvatar, state.Config.SourceAvatar);
}Mock implementations for testing:
public class MockWizardView : IWizardView
{
public bool NextButtonWasCalled { get; private set; }
public void ShowNextButton()
{
NextButtonWasCalled = true;
}
}Create build tools with Node.js and TypeScript:
// create-unitypackage.ts
import * as fs from 'fs';
import * as path from 'path';
async function createUnityPackage() {
// Process to create Unity package
}Generate documentation site:
npm run docs:build
# Build results generated in docs/.vitepress/dist/OpenFitter is realized by combining the following technologies:
- RBF Deformation: Smooth and natural clothing fitting
- Blender Integration: Powerful 3D processing engine
- Unity Editor Extension: User-friendly interface
- Asynchronous Processing: Responsive user experience
- Modular Design: Maintainable and extensible structure
These technologies enable high-quality automatic clothing fitting.