Compare commits

...

73 Commits

Author SHA1 Message Date
nadena.dev release bot
59c256704b Release 1.13.0-alpha.1 2025-04-10 03:29:38 +00:00
bd_
c4f3728d5e chore: update changelog for stable release 2025-04-09 20:24:51 -07:00
bd_
dcda15569a
fix: merge blend tree does not correct parameter type conflicts (#1552) 2025-04-09 20:05:48 -07:00
bd_
8cba3560ce
fix: reactive object could generate inconsistent WD results (#1553) 2025-04-09 20:00:40 -07:00
bd_
17051419ec
change: force blend tree-only layers to WD ON (#1551)
Closes: #1545
2025-04-09 19:14:44 -07:00
dependabot[bot]
1a1cae4e04
chore(deps): bump actions/create-github-app-token in /.github/workflows (#1546)
Bumps [actions/create-github-app-token](https://github.com/actions/create-github-app-token) from 1 to 2.
- [Release notes](https://github.com/actions/create-github-app-token/releases)
- [Commits](https://github.com/actions/create-github-app-token/compare/v1...v2)

---
updated-dependencies:
- dependency-name: actions/create-github-app-token
  dependency-version: '2'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-09 19:07:03 -07:00
dependabot[bot]
e5e4c41b38
chore(deps): bump estree-util-value-to-estree in /docs~ (#1548)
Bumps [estree-util-value-to-estree](https://github.com/remcohaszing/estree-util-value-to-estree) from 3.1.2 to 3.3.3.
- [Release notes](https://github.com/remcohaszing/estree-util-value-to-estree/releases)
- [Commits](https://github.com/remcohaszing/estree-util-value-to-estree/compare/v3.1.2...v3.3.3)

---
updated-dependencies:
- dependency-name: estree-util-value-to-estree
  dependency-version: 3.3.3
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-09 19:06:56 -07:00
nadena.dev release bot
c7c9e23acb Release 1.13.0-alpha.0 2025-04-08 01:34:44 +00:00
bd_
5be1f13840
feat: platform support declarations (#1547) 2025-04-07 18:29:26 -07:00
nadena.dev release bot
420f9b00b1 Release 1.12.3 2025-04-05 21:55:36 +00:00
bd_
45b5db46c5 chore(deps): update NDMF dependency 2025-04-05 14:50:19 -07:00
bd_
03ee9d6048
fix: incorrect WD matching handling for single-animation-clip layers (#1542)
Evidently, unity has special handling specifically for single-state layers with a blend tree, but _not_ for single-state layers with an animation clip.

Closes: #1541
2025-04-05 14:20:03 -07:00
dependabot[bot]
897d168137
chore(deps): bump image-size from 1.1.1 to 1.2.1 in /docs~ (#1535)
Bumps [image-size](https://github.com/image-size/image-size) from 1.1.1 to 1.2.1.
- [Release notes](https://github.com/image-size/image-size/releases)
- [Commits](https://github.com/image-size/image-size/compare/v1.1.1...v1.2.1)

---
updated-dependencies:
- dependency-name: image-size
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-04-05 11:40:05 -07:00
nadena.dev release bot
400960257e Release 1.12.2 2025-04-03 02:44:37 +00:00
bd_
f0fcbb66b1
fix: animated parameters in merge motion aren't renamed (#1537)
* fix: animated parameters in merge motion aren't renamed

Closes: #1536
2025-04-02 19:39:34 -07:00
nadena.dev release bot
7fd35bb49a Release 1.12.1 2025-04-02 02:22:57 +00:00
bd_
bc4c6628ee chore(deps): update NDMF dep 2025-04-01 19:16:16 -07:00
bd_
b733ce2e4d
fix: MA breaks in new VRCSDK projects (#1532) 2025-04-01 19:01:37 -07:00
bd_
3324d3f71b docs: fix CHANGELOG 2025-03-31 22:39:35 -07:00
nadena.dev release bot
c3d2cfb29f Release 1.12.0 2025-04-01 05:10:29 +00:00
bd_
7610020c3b chore(ci): fix typo 2025-03-31 22:05:48 -07:00
bd_
89de978c77 chore(ci): fix typo 2025-03-31 21:39:33 -07:00
bd_
db9389052c chore(deps): update NDMF dependency 2025-03-31 18:53:19 -07:00
bd_
81aed5b798
fix: compatibility issue with lilycalInventory (#1531)
The early animator cloning logic was dropped in refactoring, put it back.
2025-03-30 23:00:12 +00:00
bd_
706ce7aa2f
feat: use stable identifiers for MA Menu Items (#1530) 2025-03-30 18:07:48 +00:00
nadena.dev release bot
b75e74ef84 Release 1.12.0-rc.1 2025-03-28 02:15:53 +00:00
bd_
8ef4cf6328
feat: MA Parameters auto-rename now uses stable names (#1529)
Closes: #1527, #1430
2025-03-23 13:50:59 -07:00
nadena-dev-ci
c521bd7721
Update source file en-US.json (#1526) 2025-03-23 19:22:08 +00:00
bd_
e46e958f39
fix: match WD = off setting is not respected (#1528)
Closes: #1519
2025-03-23 18:34:19 +00:00
bd_
8a45515af0
chore(docs): update merge motion screenshots (#1525)
Closes: #1517
2025-03-23 02:54:15 +00:00
bd_
36b442f904
feat: allow opt-out from MMD handling (#1524)
Closes: #1518
2025-03-23 02:51:23 +00:00
bd_
124392c422
chore(docs): adjust docs translation (#1523)
Closes: #1521
2025-03-23 02:46:40 +00:00
bd_
dff7f03c2f
fix: convert constraints fails to convert animations (#1522)
Closes: #1520
2025-03-23 01:57:04 +00:00
nadena.dev release bot
713a0d3b1d Release 1.12.0-rc.0 2025-03-22 04:43:16 +00:00
nadena-dev-ci
e2a02982d5
New Crowdin updates (#1516)
* New translations en-us.json (Japanese)

* New translations en-us.json (Korean)

* New translations en-us.json (Chinese Simplified)

* New translations en-us.json (Chinese Traditional)

* Update source file en-US.json

* New translations en-us.json (Japanese)
2025-03-21 21:38:09 -07:00
bd_
672dd8b31f chore: update NDMF dependency 2025-03-21 21:34:28 -07:00
bd_
6175e20e46
fix: expressions menu icon compression breaks on iOS builds (#1513) 2025-03-22 03:25:00 +00:00
bd_
fce938820b
fix: compiler warnings (#1515) 2025-03-22 03:20:23 +00:00
bd_
34deac5681
feat: support merging animation clips in Merge Blend Tree (#1514)
This renames Merge Blend Tree to Merge Motion, and expands it to support arbitrary motions.

Closes: #1438
2025-03-22 03:10:45 +00:00
bd_
b49e5cb460
fix: non-divisible-by-four texture sizes breaks automatic expressions menu icon compression (#1508)
Closes: #1477
2025-03-19 03:25:30 +00:00
bd_
3165d471b5 chore(changelog): fix header after release 2025-03-16 21:14:45 -07:00
bd_
2d59c74066 fix(ci): perform-release workflow doesn't update JP CHANGELOGs 2025-03-16 21:13:33 -07:00
nadena.dev release bot
55d744885f Release 1.12.0-beta.0 2025-03-17 04:09:15 +00:00
bd_
318d65f3b5
fix: DelayDisable unnecessarily tracks no-longer-relevant game objects (#1504)
Closes: #1469
2025-03-17 03:58:05 +00:00
bd_
aac70873c5
chore(deps): Update NDMF dependency (#1503)
Closes: #1410
2025-03-17 03:37:02 +00:00
bd_
5a17d6ea9a
feat: World Fixed Object now uses VRCParentConstraint and supports Android builds (#1502)
Closes: #1417
2025-03-17 03:11:58 +00:00
bd_
62fd986fd0
fix: unity editor shortcuts break while editing MA Parameters text fields (#1501)
Closes: #1414
2025-03-17 02:58:37 +00:00
bd_
39b4df8367
fix: missing japanese docs for World Scale Object (#1500)
Closes: #1498
2025-03-15 04:02:21 +00:00
Ao_425
fc9b2683c8
chore: Create toggle with submenu in "CreateToggleForSelection" (#1437)
* chore: refactor and Ignore GameObjects with submenu for CreateToggleForSelection

* chore: create toggle with submenu in CreateToggleForSelection

* chore: use simple suffixes

* chore: update CHANGELOG

* fix: update CHANGELOG

---------

Co-authored-by: bd_ <bd_@nadena.dev>
2025-03-15 03:54:15 +00:00
bd_
98311f11f8
fix: RC-toggled audio sources are always active when animations are blocked (#1499)
Closes: #1496
2025-03-15 03:49:28 +00:00
bd_
2557972461
feat: ensure that correct layers are toggled off in MMD worlds, even after messing with layer order (#1489)
We make the assumption that the MMD world will _specifically_
be disabling layers 1 and 2.
2025-03-14 20:44:50 -07:00
bd_
9510c56f7a
docs: add changelog to docs site (#1497)
Closes: #1479
2025-03-13 19:49:39 -07:00
dependabot[bot]
9418b00b54
chore(deps): bump @babel/runtime from 7.24.7 to 7.26.10 in /docs~ (#1493)
Bumps [@babel/runtime](https://github.com/babel/babel/tree/HEAD/packages/babel-runtime) from 7.24.7 to 7.26.10.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.26.10/packages/babel-runtime)

---
updated-dependencies:
- dependency-name: "@babel/runtime"
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-13 04:10:55 +00:00
dependabot[bot]
61f11ff836
chore(deps): bump @babel/helpers from 7.24.7 to 7.26.10 in /docs~ (#1494)
Bumps [@babel/helpers](https://github.com/babel/babel/tree/HEAD/packages/babel-helpers) from 7.24.7 to 7.26.10.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.26.10/packages/babel-helpers)

---
updated-dependencies:
- dependency-name: "@babel/helpers"
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-13 04:10:41 +00:00
dependabot[bot]
2823696af9
chore(deps): bump @babel/runtime-corejs3 in /docs~ (#1495)
Bumps [@babel/runtime-corejs3](https://github.com/babel/babel/tree/HEAD/packages/babel-runtime-corejs3) from 7.26.7 to 7.26.10.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.26.10/packages/babel-runtime-corejs3)

---
updated-dependencies:
- dependency-name: "@babel/runtime-corejs3"
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-12 21:10:14 -07:00
bd_
45352296e9 Revert "ci: testing"
This reverts commit 4323b40362c357847603e65a7f34a33b26962987.
2025-03-12 21:10:02 -07:00
bd_
4323b40362 ci: testing 2025-03-12 21:09:18 -07:00
bd_
57f1851cdd ci: exclude dependabot from changelog checks 2025-03-12 21:08:05 -07:00
bd_
494ad1c4d9
ci: fix missing logo assets (#1492)
Closes: #1490
2025-03-13 03:24:35 +00:00
bd_
2e79c9b195 ci: enable CHANGELOG validation
Closes: #1478
2025-03-12 20:16:49 -07:00
bd_
7182baca47
fix: additional test failures (#1491) 2025-03-13 03:05:58 +00:00
nadena-dev-ci
71a0d82c66
New Crowdin updates (#1485)
* Update source file en-US.json

* New translations en-us.json (Japanese)
2025-03-13 02:34:28 +00:00
bd_
4c44c576de
fix: Merge Animator in replace mode breaks Merge Blend Tree (#1488) 2025-03-12 02:21:21 +00:00
bd_
ec73eb6225
fix: test failures in Merge Armature (#1487)
... apparently auto-merge wasn't set properly to check for unit test completion. oops.
2025-03-12 02:19:05 +00:00
bd_
295a46ec12
feat: support merging humanoid bones with PBs in limited cases (#1429)
* feat: support merging humanoid bones with PBs in limited cases

This change adds support for merging humanoid bones that are a target of PhysBones, provided that all humanoid children are excluded from that PhysBone (either with a direct ignores field, or using PB Blocker).

Note: Because this is a significant expansion of support, this will need to wait for a minor release to maintain semver semantics.

Closes: #1406
2025-03-12 01:51:47 +00:00
bd_
fa004b2db5
fix: Merge Animator should not adjust WD in single state or additive layers (#1483) 2025-03-10 21:09:27 -07:00
bd_
f6362cdbc2
chore: re-enable disabled test (#1484) 2025-03-10 21:09:11 -07:00
bd_
cbf7fa4233 chore: bump NDMF dependency 2025-03-10 21:01:42 -07:00
dependabot[bot]
a7906e4fd6
chore(deps): bump prismjs from 1.29.0 to 1.30.0 in /docs~ (#1480)
Bumps [prismjs](https://github.com/PrismJS/prism) from 1.29.0 to 1.30.0.
- [Release notes](https://github.com/PrismJS/prism/releases)
- [Changelog](https://github.com/PrismJS/prism/blob/master/CHANGELOG.md)
- [Commits](https://github.com/PrismJS/prism/compare/v1.29.0...v1.30.0)

---
updated-dependencies:
- dependency-name: prismjs
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2025-03-10 20:43:30 -07:00
bd_
f0a61fe55a
feat: Merge Animator replacement mode (#1482)
Closes: #330
Closes: #1308
2025-03-10 20:37:29 -07:00
bd_
7abfb021e3 feat: World Scale Object 2025-03-10 20:36:17 -07:00
bd_
903f230633 docs(changelog): fix changelog issues 2025-03-10 19:13:28 -07:00
nadena.dev release bot
be729c8f53 Release 1.12.0-alpha.2 2025-03-10 05:19:45 +00:00
197 changed files with 13894 additions and 486 deletions

View File

@ -4,7 +4,7 @@
"version": "3.7.4"
},
"nadena.dev.ndmf": {
"version": "1.7.0-alpha.2"
"version": "1.8.0-alpha.4"
}
},
"locked": {
@ -19,7 +19,7 @@
"dependencies": {}
},
"nadena.dev.ndmf": {
"version": "1.7.0-alpha.2"
"version": "1.8.0-alpha.4"
}
}
}

22
.github/gen-docs-changelog.pl vendored Executable file
View File

@ -0,0 +1,22 @@
#!/usr/bin/perl
use strict;
use warnings;
# We want to skip two sections - the main header, then up to the first version header.
# In a prerelease, we only want to skip the first section (not including the unreleased header)
if ($ENV{PRERELEASE} eq 'false') {
while (<>) {
if (/^\## /) { last; }
}
}
while (<>) {
if (/^## /) { print; last; }
}
while (<>) {
print;
}

View File

@ -23,6 +23,11 @@ on:
description: 'build the latest release'
type: boolean
required: false
prerelease:
description: 'use prerelease changelog'
type: boolean
required: false
default: true
jobs:
build-docs:
@ -67,6 +72,18 @@ jobs:
BASEURL="/${{ inputs.path }}/" perl -i -p -e "s{baseUrl: '/'}{baseUrl: '\$ENV{BASEURL}'}" docs~/docusaurus.config.js
cat docs~/docusaurus.config.js
- name: Format changelogs
run: |
SUFFIX=""
export PRERELEASE=${{ inputs.prerelease && 'true' || 'false' }}
if [ ${{ inputs.prerelease }} == true ]; then
SUFFIX="-PRERELEASE"
fi
perl -n .github/gen-docs-changelog.pl < CHANGELOG$SUFFIX.md >> docs~/docs/changelog.md
perl -n .github/gen-docs-changelog.pl < CHANGELOG$SUFFIX''-jp.md >> docs~/i18n/ja/docusaurus-plugin-content-docs/current/changelog.md
- name: Build docs
run: |
cd docs~

58
.github/workflows/changelog-check.yml vendored Normal file
View File

@ -0,0 +1,58 @@
# From https://github.com/anatawa12/AvatarOptimizer/blob/ccb863243433019f323c23a3a2e24b27e15b2f6c/.github/workflows/changelog-check.yml
# Copyright 2022 anatawa12
# MIT license.
# this workflow checks CHANGELOG.md & CHANGELOG-SNAPSHOTS.md is updated correctly
# to skip this check, include `NO-CHANGELOG` for CHANGELOG.md
# and `NO-CHANGELOG-PRERELEASE` for CHANGELOG-PRERELEASE.md in tags of PR.
# also, this action ignores `dependencies` pull requests (expected to be generated by dependabot)
name: CHANGELOG check
on:
pull_request_target:
branches: [ main, main-* ]
types: [ opened, synchronize, reopened, ready_for_review, labeled, unlabeled ]
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
releasenote-check:
if: ${{ ! github.event.pull_request.draft }}
runs-on: ubuntu-latest
strategy:
matrix:
file: [CHANGELOG.md, CHANGELOG-jp.md, CHANGELOG-PRERELEASE.md, CHANGELOG-PRERELEASE-jp.md]
env:
NO_CHANGELOG: ${{
contains(github.event.pull_request.labels.*.name, 'NO-CHANGELOG')
|| contains(github.event.pull_request.labels.*.name, 'documentation')
|| contains(github.event.pull_request.labels.*.name, 'localization')
|| contains(github.event.pull_request.labels.*.name, 'ci')
|| contains(github.event.pull_request.labels.*.name, 'refactor')
|| startsWith(github.event.pull_request.head.label, 'bdunderscore:dependabot/')
|| '' }}
SNAPSHOT_ONLY: ${{ contains(github.event.pull_request.labels.*.name, 'PRERELEASE-ONLY') || '' }}
# Steps represent a sequence of tasks that will be executed as part of the job
steps:
- name: Dump GitHub context
env:
GITHUB_CONTEXT: ${{ toJson(github) }}
run: echo "$GITHUB_CONTEXT"
- name: Fetch pull_request info
env:
GH_REPO: ${{ github.repositoryUrl }}
GH_TOKEN: ${{secrets.GITHUB_TOKEN}}
PR_NUM: ${{ github.event.number }}
run: |
gh pr view $PR_NUM --json=files | jq --raw-output '.files[].path' > files.txt
- name: Changelog check for ${{ matrix.file }}
if: always() && !env.NO_CHANGELOG && (startsWith(matrix.file, 'CHANGELOG-PRERELEASE') || !env.SNAPSHOT_ONLY)
run: |
if ! grep -e '^${{ matrix.file }}$' < files.txt > /dev/null; then
echo "::error::An entry in ${{ matrix.file }} is required for this PR."
echo "If this change is only relevant between snapshot versions: Add the label 'PRERELEASE-ONLY' to this PR." >> $GITHUB_STEP_SUMMARY
echo "If this change does not warrant any release notes: Add the label 'NO-CHANGELOG' to this PR." >> $GITHUB_STEP_SUMMARY
exit 1
fi

View File

@ -40,11 +40,13 @@ jobs:
build-docs:
name: Build documentation (latest release)
# TODO - update to build-docs.yml
uses: bdunderscore/modular-avatar/.github/workflows/build-test-docs.yml@main
needs:
- snapshot-docs
with:
ref: docs-snapshot
prerelease: false
build-docs-dev:
name: Build documentation (main branch)
@ -53,6 +55,7 @@ jobs:
ref: main
path: dev
artifact: docs-dev
prerelease: true
deploy-docs:
name: Deploy documentation

View File

@ -56,7 +56,7 @@ jobs:
run: echo "$GITHUB_CONTEXT"
# https://github.com/orgs/community/discussions/13836#discussioncomment-8535364
- uses: actions/create-github-app-token@v1
- uses: actions/create-github-app-token@v2
id: app-token
with:
app-id: ${{ vars.RELEASER_APP_ID }}
@ -108,6 +108,18 @@ jobs:
submodules: recursive
token: ${{ steps.app-token.outputs.token }}
- name: Checkout logo assets
uses: actions/checkout@v4
if: ${{ github.event.inputs.release_kind != 'adhoc' }}
with:
repository: bdunderscore/modular-avatar-images
path: .github/image-assets
- name: Inject logo assets
if: ${{ github.event.inputs.release_kind != 'adhoc' }}
run: |
cp -f .github/image-assets/img/logo/ma_logo.png Editor/Images/logo.png
cp -f .github/image-assets/img/logo/ma_icon.png Runtime/Icons/Icon_MA_Script.png
- name: Check semver syntax
if: steps.check-tag.outputs.need-new-tag == 'true'
id: semver-check
@ -136,9 +148,12 @@ jobs:
if [ "${{ env.PRERELEASE }}" == "true" ]; then
./.github/cut-changelog.pl CHANGELOG-PRERELEASE.md .github/CHANGELOG-HEADER.md ${{ env.VERSION }} .github/relnote-en.md
./.github/cut-changelog.pl CHANGELOG-PRERELEASE-jp.md .github/CHANGELOG-HEADER.md ${{ env.VERSION }} .github/relnote-jp.md
else
./.github/cut-changelog.pl CHANGELOG-PRERELEASE.md .github/CHANGELOG-HEADER.md ${{ env.VERSION }}
./.github/cut-changelog.pl CHANGELOG-PRERELEASE-jp.md .github/CHANGELOG-HEADER.md ${{ env.VERSION }}
./.github/cut-changelog.pl CHANGELOG.md .github/CHANGELOG-HEADER.md ${{ env.VERSION }} .github/relnote-en.md
./.github/cut-changelog.pl CHANGELOG-jp.md .github/CHANGELOG-HEADER.md ${{ env.VERSION }} .github/relnote-jp.md
fi
echo Version ${{ env.VERSION }} > release-note.md
@ -150,7 +165,10 @@ jobs:
fi
echo '## Notable changes' >> release-note.md
cat .github/relnote-en.md >> release-note.md
echo >> release-note.md
echo '## 主な変更点' >> release-note.md
cat .github/relnote-jp.md >> release-note.md
- name: Upload CHANGELOG.md
if: ${{ github.event.inputs.release_kind == 'stable' }}
uses: actions/upload-artifact@v4

View File

@ -8,12 +8,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
### Added
- Added CHANGELOG files
### Fixed
### Changed
- [#1476] ModularAvatarMergeAnimator と ModularAvatarMergeParameter を新しい NDMF API (`IVirtualizeMotion``IVirtualizeAnimatorController`) を使用するように変更
### Removed
@ -21,6 +19,111 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Deprecated
## [1.13.0-alpha.1] - [2025-04-10]
### Fixed
- [#1552] Merge Blend Treeにて、メインアバターFXレイヤーと同じ名前のintやboolパラメーターがBlend Treeに含まれている場合、
パラメーター型が修正されない問題を修正
- [#1553] リアクティブコンポーネントが生成するステートに、WD設定が正しくない問題を修正
### Changed
- [#1551] Merge Animatorは、遷移のない単一のstateを持つブレンドツリーのレイヤーに対して常にWDをONに設定します。
- 一部、以前の挙動に依存したアセットとの互換性を向上させるための変更です。
## [1.13.0-alpha.0] - [2025-04-08]
### Added
- (実験的機能) VRC以外のプラットフォームのサポートを有効化
## [1.12.3] - [2025-04-05]
### Fixed
- Additiveレイヤーの問題を修正NDMFバージョンアップグレードによって修正
### Changed
- [#1542] Merge Animatorは、アニメーションクリップを含む単一のstateを持つレイヤーに対してWD設定を一致させるが、
  ブレンドツリーを含む場合は一致させないように変更されました。
- これにより、1.12で導入された互換性の問題が修正されます1.12.0では、単一のstateアニメーションクリップに対してWD設定
と一致しないように変更されました)。
## [1.12.2] - [2025-04-03]
### Fixed
- [#1537] アニメーターパラメーターをアニメーションさせるカーブが、`Merge Motion` コンポーネントを使用して追加された場合、
`Rename Parameters` によって更新されない問題を修正``
## [1.12.1] - [2025-04-02]
### Fixed
- [#1532] Modular Avatarが新しく作成したプロジェクトでコンパイラエラーを出す問題を修正
## [1.12.0] - [2025-04-01]
### Fixed
- [#1531] lylicalInventoryとの互換性問題を修正
### Changed
- [#1530] `MA Menu Item`の自動パラメーター機能も、オブジェクトのパスに基づいて名前を割り当てるようになりました。
## [1.12.0-rc.1] - [2025-03-28]
### Added
- [#1524] MMDワールド対応をアバター全体で無効にする機能を追加
### Fixed
- [#1522] `Convert Constraints` がアニメーション参照を変換できない問題を修正
- [#1528] `Merge Animator``アバターのWrite Defaults設定に合わせる` 設定を無視し、常に合わせてしまう問題を修正
### Changed
- [#1529] `MA Parameters` の自動リネームは、オブジェクトのパスに基づいて新しい名前を割り当てるように変更されました。これにより、
`MA Sync Parameter Sequence` との互換性が向上します。
- `MA Sync Parameter Sequence` を使用している場合は、このバージョンに更新した後、SyncedParamsアセットを空にして、
すべてのプラットフォームを再アップロードすることをお勧めします。
## [1.12.0-rc.0] - [2025-03-22]
### Fixed
- [#1508] テクスチャのサイズが4の倍数でない場合に、エクスプレッションメニューアイコンの自動圧縮が失敗する問題を修正
- [#1513] iOSビルドでエクスプレッションメニューアイコンの圧縮が壊れる問題を修正
### Changed
- [#1514] `Merge Blend Tree``Merge Motion (Blend Tree)` に改名され、アニメーションクリップにも対応するようになりました
## [1.12.0-beta.0] - [2025-03-17]
### Added
- [#1497] CHANGELOGをドキュメンテーションサイトに追加
- [#1482] `Merge Animator` に既存のアニメーターコントローラーを置き換える機能を追加
- [#1481] [World Scale Object](https://m-a.nadena.dev/dev/ja/docs/reference/world-scale-object)を追加
- [#1489] [`MA MMD Layer Control`](https://modular-avatar.nadena.dev/docs/general-behavior/mmd)を追加
### Fixed
- [#1492] 前回のプレリリースでアイコンとロゴアセットが間違っていた問題を修正
- [#1501] MA Parametersコンポーネントのテキスト入力欄を編集する際にUnityのキーボードショートカットが機能しない問題を修正
- [#1410] 同期レイヤー内のモーションオーバーライドがBone Proxy/Merge Armatureオブジェクトの移動に対して更新されない問題を修正
- [#1504] 一部の状況で内部の`DelayDisable`レイヤーが不要なオブジェクトを参照しないように変更
- これにより、オブジェクトがアニメーションされているかどうかを追跡するAAOなどのツールとの互換性が向上します
### Changed
- [#1483] Merge Animator の 「アバターの Write Defaults 設定に合わせる」設定では、Additiveなレイヤー、および単一Stateかつ遷移のないレイヤー
 に対してはWrite Defaultsを調整しないように変更。
- [#1429] Merge Armature は、特定の場合にPhysBoneに指定されたヒューマイドボーンをマージできるようになりました。
- 具体的には、子ヒューマイドボーンがある場合はPhysBoneから除外される必要があります。
- [#1437] Create Toggle for Selectionにおいて、複数選択時時に必要に応じてサブメニューを生成し、子としてトグルを生成するように変更されました。
- [#1499] `Object Toggle`で制御される`Audio Source`がアニメーションブロックされたときに常にアクティブにならないように、
アニメーションがブロックされたときにオーディオソースを無効にするように変更。
- [#1489] `Merge Blend Tree` やリアクティブコンポーネントとMMDワールドの互換性の問題を修正。
詳細は[ドキュメント](https://modular-avatar.nadena.dev/docs/general-behavior/mmd)を参照してください。
- [#1502] `World Fixed Object``VRCParentConstraint` を使用するようになり、Androidビルドで使用可能になりました。
## [1.12.0-alpha.2] - [2025-03-10]
### Added
- Added CHANGELOG files
### Changed
- [#1476] ModularAvatarMergeAnimator と ModularAvatarMergeParameter を新しい NDMF API (`IVirtualizeMotion``IVirtualizeAnimatorController`) を使用するように変更
## Older versions
Please see CHANGELOG.md

View File

@ -19,7 +19,104 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Deprecated
## [1.7.0-alpha.2] - [2025-03-10]
## [1.13.0-alpha.1] - [2025-04-10]
### Fixed
- [#1552] Merge Blend Tree failed to correct parameter types when the main avatar FX layer contained an int or bool
parameter with the same name as one used in the blend tree.
- [#1553] Reactive components might generate states with incorrect write default settings
### Changed
- [#1551] Merge Animator will always set WD ON for single-state blendtree layers with no any state transitions.
- This fixes compatibility issues with assets which relied on the prior behavior.
## [1.13.0-alpha.0] - [2025-04-08]
### Added
- (Experimental feature) Enabled support for non-VRC platforms
## [1.12.3] - [2025-04-05]
### Fixed
- Fixed issues with additive layers (via NDMF version upgrade)
### Changed
- [#1542] Merge Animator now will match WD settings for layers with a single state containing an animation clip,
but not if it contains a blend tree. This fixes some compatibility issues introduced in 1.12 (where the behavior
was changed to not match WD settings for single-state animation clips).
## [1.12.2] - [2025-04-03]
### Fixed
- [#1537] Curves which animated animator parameters, when added using a `Merge Motion` component, would not be updated by
`Rename Parameters`
## [1.12.1] - [2025-04-02]
### Fixed
- [#1532] Modular Avatar has compiler errors in a newly created project
## [1.12.0] - [2025-04-01]
### Fixed
- [#1531] Fix compatibility issue with lylicalInventory
### Changed
- [#1530] `MA Menu Item` auto parameters now also assign names based on object paths
## [1.12.0-rc.1] - [2025-03-28]
### Added
- [#1524] Added support for disabling MMD world handling at an avatar level
### Fixed
- [#1522] `Convert Constraints` failed to convert animation references
- [#1528] `Merge Animator` ignored the `Match Avatar Write Defaults` setting and always matched
### Changed
- [#1529] `MA Parameters` auto-rename now assigns new names based on the path of the object. This should improve
compatibility with `MA Sync Parameter Sequence`
- If you are using `MA Sync Parameter Sequence`, it's a good idea to empty your SyncedParams asset and reupload all
platforms after updating to this version.
## [1.12.0-rc.0] - [2025-03-22]
### Fixed
- [#1508] Fix an issue where automatic compression of expressions menu icons would fail when the texture dimensions were
not divisible by four.
- [#1513] Expression menu icon compression broke on iOS builds
### Changed
- [#1514] `Merge Blend Tree` is now `Merge Motion (Blend Tree)` and supports merging animation clips as well as blend trees
## [1.12.0-beta.0] - [2025-03-17]
### Added
- [#1497] Added changelog to docs site
- [#1482] Added support for replacing pre-existing animator controllers to `Merge Animator`
- [#1481] Added [World Scale Object](https://m-a.nadena.dev/dev/docs/reference/world-scale-object)
- [#1489] Added [`MA MMD Layer Control`](https://modular-avatar.nadena.dev/docs/general-behavior/mmd)
### Fixed
- [#1492] Fixed incorrect icon and logo assets in prior prerelease
- [#1489] Fixed compatibility issues between `Merge Blend Tree` or reactive components and MMD worlds.
See [documentation](https://modular-avatar.nadena.dev/docs/general-behavior/mmd) for details on the new handling.
- [#1501] Unity keyboard shortcuts don't work when editing text fields on the MA Parameters component
- [#1410] Motion overrides on synced layers are not updated for Bone Proxy/Merge Armature object movement
- [#1504] The internal `DelayDisable` layer no longer references unnecessary objects in some situations
- This helps improve compatibility with AAO and other tools that track whether objects are animated
### Changed
- [#1483] The Merge Animator "Match Avatar Write Defaults" option will no longer adjust write defaults on states in
additive layers, or layers with only one state and no transitions.
- [#1429] Merge Armature will now allow you to merge humanoid bones with PhysBones attached in certain cases.
- Specifically, child humanoid bones (if there are any) must be excluded from all attached Physbones.
- [#1437] Create Toggle for Selection now creates submenus as necessary when multiple items are selected, and creates toggles as children.
- [#1499] When an audio source is controlled by an Object Toggle, disable the audio source when animations are blocked
to avoid it unintentionally being constantly active.
- [#1502] `World Fixed Object` now uses `VRCParentConstraint` and is therefore compatible with Android builds
## [1.12.0-alpha.2] - [2025-03-10]
### Added
- Added CHANGELOG files

View File

@ -9,13 +9,11 @@ Modular Avatarの主な変更点をこのファイルで記録しています。
## [Unreleased]
### Added
- CHANGELOGファイルを追加
- (実験的機能) VRC以外のプラットフォームのサポートを有効化
### Fixed
- [#1460] パラメーターアセットをMA Parametersにインポートするとき、ローカルのみのパラメーターが間違ってアニメーターのみ扱いになる問題を修正
### Changed
- [#1476] ModularAvatarMergeAnimator と ModularAvatarMergeParameter を新しい NDMF API (`IVirtualizeMotion``IVirtualizeAnimatorController`) を使用するように変更
### Removed
@ -23,6 +21,75 @@ Modular Avatarの主な変更点をこのファイルで記録しています。
### Deprecated
## [1.12.4] - [2025-04-10]
### Fixed
- [#1552] Merge Blend Treeにて、メインアバターFXレイヤーと同じ名前のintやboolパラメーターがBlend Treeに含まれている場合、
パラメーター型が修正されない問題を修正
- [#1553] リアクティブコンポーネントが生成するステートに、WD設定が正しくない問題を修正
### Changed
- [#1551] Merge Animatorは、遷移のない単一のstateを持つブレンドツリーのレイヤーに対して常にWDをONに設定します。
- 一部、以前の挙動に依存したアセットとの互換性を向上させるための変更です。
## [1.12.3] - [2025-04-05]
### Fixed
- Additiveレイヤーの問題を修正NDMFバージョンアップグレードによって修正
### Changed
- [#1542] Merge Animatorは、アニメーションクリップを含む単一のstateを持つレイヤーに対してWD設定を一致させるが、
  ブレンドツリーを含む場合は一致させないように変更されました。
- これにより、1.12で導入された互換性の問題が修正されます1.12.0では、単一のstateアニメーションクリップに対してWD設定
と一致しないように変更されました)。
## [1.12.2] - [2025-04-03]
### Fixed
- [#1537] アニメーターパラメーターをアニメーションさせるカーブが、`Merge Motion` コンポーネントを使用して追加された場合、
`Rename Parameters` によって更新されない問題を修正``
## [1.12.1] - [2025-04-02]
### Fixed
- [#1532] Modular Avatarが新しく作成したプロジェクトでコンパイラエラーを出す問題を修正
## [1.12.0] - [2025-04-01]
### Added
- CHANGELOGファイルを追加
- [#1482] `Merge Animator` に既存のアニメーターコントローラーを置き換える機能を追加
- [#1481] [World Scale Object](https://m-a.nadena.dev/ja/docs/reference/world-scale-object)を追加
- [#1489] [`MA MMD Layer Control`](https://modular-avatar.nadena.dev/docs/general-behavior/mmd)を追加
### Fixed
- [#1460] パラメーターアセットをMA Parametersにインポートするとき、ローカルのみのパラメーターが間違ってアニメーターのみ扱いになる問題を修正
- [#1489] `Merge Blend Tree` やリアクティブコンポーネントとMMDワールドの互換性の問題を修正。
- 詳細は[ドキュメント](https://modular-avatar.nadena.dev/docs/general-behavior/mmd)を参照してください。
- この動作を無効にするには、新しい `MA VRChat Settings` コンポーネントをアバターの適当なところに追加して、適切な設定を無効にしてください。
- [#1501] MA Parametersコンポーネントのテキスト入力欄を編集する際にUnityのキーボードショートカットが機能しない問題を修正
- [#1410] 同期レイヤー内のモーションオーバーライドがBone Proxy/Merge Armatureオブジェクトの移動に対して更新されない問題を修正
- [#1504] 一部の状況で内部の`DelayDisable`レイヤーが不要なオブジェクトを参照しないように変更
- これにより、オブジェクトがアニメーションされているかどうかを追跡するAAOなどのツールとの互換性が向上します
- [#1508] テクスチャのサイズが4の倍数でない場合に、エクスプレッションメニューアイコンの自動圧縮が失敗する問題を修正
- [#1513] iOSビルドでエクスプレッションメニューアイコンの圧縮処理が壊れる問題を修正
### Changed
- [#1529] `MA Parameters` の自動リネームと `MA Menu Item` の自動パラメーター機能は、オブジェクトのパスに基づいて名前
を割り当てるように変更されました。
- `MA Sync Parameter Sequence` を使用している場合は、このバージョンに更新した後、SyncedParamsアセットを空にして、
すべてのプラットフォームを再アップロードすることをお勧めします。
- [#1514] `Merge Blend Tree``Merge Motion (Blend Tree)` に改名され、アニメーションクリップにも対応するようになりました
- [#1476] ModularAvatarMergeAnimator と ModularAvatarMergeParameter を新しい NDMF API (`IVirtualizeMotion``IVirtualizeAnimatorController`) を使用するように変更
- [#1483] Merge Animator の 「アバターの Write Defaults 設定に合わせる」設定では、Additiveなレイヤー、および単一Stateかつ遷移のないレイヤー
 に対してはWrite Defaultsを調整しないように変更。
- [#1429] Merge Armature は、特定の場合にPhysBoneに指定されたヒューマイドボーンをマージできるようになりました。
- 具体的には、子ヒューマイドボーンがある場合はPhysBoneから除外される必要があります。
- [#1437] Create Toggle for Selectionにおいて、複数選択時時に必要に応じてサブメニューを生成し、子としてトグルを生成するように変更されました。
- [#1499] `Object Toggle`で制御される`Audio Source`がアニメーションブロックされたときに常にアクティブにならないように、
アニメーションがブロックされたときにオーディオソースを無効にするように変更。
- [#1502] `World Fixed Object``VRCParentConstraint` を使用するようになり、Androidビルドで使用可能になりました。
## それより前
GitHubのリリースページをご確認ください: https://github.com/bdunderscore/modular-avatar/releases

View File

@ -11,14 +11,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
### Added
- Added CHANGELOG files
- (Experimental feature) Enabled support for non-VRC platforms
### Fixed
- [#1460] When importing parameter assets in MA Parameters, "local only" parameters were incorrectly treated as
"animator only"
### Changed
- [#1476] Switch ModularAvatarMergeAnimator and ModularAvatarMergeParameter to use new NDMF APIs (`IVirtualizeMotion` and `IVirtualizeAnimatorController`)
### Removed
@ -26,6 +23,77 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
### Deprecated
## [1.12.4] - [2025-04-10]
### Fixed
- [#1552] Merge Blend Tree failed to correct parameter types when the main avatar FX layer contained an int or bool
parameter with the same name as one used in the blend tree.
- [#1553] Reactive components might generate states with incorrect write default settings
### Changed
- [#1551] Merge Animator will always set WD ON for single-state blendtree layers with no any state transitions.
- This fixes compatibility issues with assets which relied on the prior behavior.
## [1.12.3] - [2025-04-05]
### Fixed
- Fixed issues with additive layers (via NDMF version upgrade)
### Changed
- [#1542] Merge Animator now will match WD settings for layers with a single state containing an animation clip,
but not if it contains a blend tree. This fixes some compatibility issues introduced in 1.12 (where the behavior
was changed to not match WD settings for single-state animation clips).
- [#1551] Merge Animator will always set WD ON for single-state blendtree layers with no any state transitions.
## [1.12.2] - [2025-04-03]
### Fixed
- [#1537] Curves which animated animator parameters, when added using a `Merge Motion` component, would not be updated by
`Rename Parameters`
## [1.12.1] - [2025-04-02]
### Fixed
- [#1532] Modular Avatar has compiler errors in a newly created project
## [1.12.0] - [2025-04-01]
### Added
- Added CHANGELOG files
- [#1482] Added support for replacing pre-existing animator controllers to `Merge Animator`
- [#1481] Added [World Scale Object](https://m-a.nadena.dev/docs/reference/world-scale-object)
- [#1489] Added [`MA MMD Layer Control`](https://modular-avatar.nadena.dev/docs/general-behavior/mmd)
### Fixed
- [#1460] When importing parameter assets in MA Parameters, "local only" parameters were incorrectly treated as
"animator only"
- [#1489] Fixed compatibility issues between `Merge Blend Tree` or reactive components and MMD worlds.
- See [documentation](https://modular-avatar.nadena.dev/docs/general-behavior/mmd) for details on the new handling.
- To disable this behavior, attach the new `MA VRChat Settings` component to any object on your avatar and disable the appropriate setting.
- [#1501] Unity keyboard shortcuts don't work when editing text fields on the MA Parameters component
- [#1410] Motion overrides on synced layers are not updated for Bone Proxy/Merge Armature object movement
- [#1504] The internal `DelayDisable` layer no longer references unnecessary objects in some situations
- This helps improve compatibility with AAO and other tools that track whether objects are animated
- [#1508] Fix an issue where automatic compression of expressions menu icons would fail when the texture dimensions were
not divisible by four.
- [#1513] Expression menu icon compression broke on iOS builds
### Changed
- [#1529] `MA Parameters` auto-rename and `MA Menu Item`'s automatic parameter feature now assign names based on the
path of the object. This should improve compatibility with `MA Sync Parameter Sequence`
- If you are using `MA Sync Parameter Sequence`, it's a good idea to empty your SyncedParams asset and reupload all
platforms after updating to this version.
- [#1514] `Merge Blend Tree` is now `Merge Motion (Blend Tree)` and supports merging animation clips as well as blend trees
- [#1476] Switch ModularAvatarMergeAnimator and ModularAvatarMergeParameter to use new NDMF APIs (`IVirtualizeMotion` and `IVirtualizeAnimatorController`)
- [#1483] The Merge Animator "Match Avatar Write Defaults" option will no longer adjust write defaults on states in
additive layers, or layers with only one state and no transitions.
- [#1429] Merge Armature will now allow you to merge humanoid bones with PhysBones attached in certain cases.
- Specifically, child humanoid bones (if there are any) must be excluded from all attached Physbones.
- [#1437] Create Toggle for Selection now creates submenus as necessary when multiple items are selected, and creates toggles as children.
- [#1499] When an audio source is controlled by an Object Toggle, disable the audio source when animations are blocked
to avoid it unintentionally being constantly active.
- [#1502] `World Fixed Object` now uses `VRCParentConstraint` and is therefore compatible with Android builds
## Older versions
Please see the github releases page at https://github.com/bdunderscore/modular-avatar/releases

View File

@ -20,9 +20,25 @@ namespace nadena.dev.modular_avatar.animation
protected override void Execute(BuildContext context)
{
var asc = context.Extension<AnimatorServicesContext>();
var activeProxies = context.GetState<ReadablePropertyExtension.Retained>().proxyProps;
var activeProxies = context.GetState<ReadablePropertyExtension.Retained>().proxyProps
.ToDictionary(kv => kv.Key, kv => kv.Value);
if (activeProxies.Count == 0) return;
// Filter any proxies not used in animator transitions
var usedProxies = asc.ControllerContext.Controllers[VRCAvatarDescriptor.AnimLayerType.FX]
.AllReachableNodes().OfType<VirtualTransitionBase>()
.SelectMany(t => t.Conditions)
.Select(c => c.parameter)
.ToHashSet();
foreach (var proxyBinding in activeProxies.ToList())
{
if (!usedProxies.Contains(proxyBinding.Value))
{
activeProxies.Remove(proxyBinding.Key);
}
}
var fx = asc.ControllerContext.Controllers[VRCAvatarDescriptor.AnimLayerType.FX];
if (fx == null) return;

View File

@ -0,0 +1,248 @@
#nullable enable
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using nadena.dev.modular_avatar.core;
using nadena.dev.modular_avatar.core.editor;
using nadena.dev.ndmf;
using nadena.dev.ndmf.animator;
using UnityEditor;
using UnityEditor.Animations;
using UnityEngine;
using VRC.SDK3.Avatars.Components;
using VRC.SDKBase;
using BuildContext = nadena.dev.ndmf.BuildContext;
using Object = UnityEngine.Object;
namespace nadena.dev.modular_avatar.animation
{
internal class MMDRelayState
{
internal HashSet<VirtualLayer> mmdAffectedOriginalLayers = new();
}
[RunsOnPlatforms(WellKnownPlatforms.VRChatAvatar30)]
internal class MMDRelayEarlyPass : Pass<MMDRelayEarlyPass>
{
protected override void Execute(BuildContext context)
{
if (!MMDRelayPass.ShouldRun(context)) return;
var asc = context.Extension<AnimatorServicesContext>();
if (asc.ControllerContext.Controllers.TryGetValue(VRCAvatarDescriptor.AnimLayerType.FX, out var fx))
{
context.GetState<MMDRelayState>().mmdAffectedOriginalLayers = new HashSet<VirtualLayer>(
fx.Layers.Skip(1).Take(2)
);
}
}
}
/// <summary>
/// Many MMD worlds animate the first three FX layers to weight zero. When MA injects new layers, this can hit
/// unintended layers (eg the RC base state layer).
/// To work around this, we'll inject a layer which will relay its active state into a parameter; then, we add a
/// layer to relay this to layers which should be affected. Finally, any layer which _shouldn't_ be affected is
/// pushed out of the first three layers by injecting dummy layers.
/// </summary>
[RunsOnPlatforms(WellKnownPlatforms.VRChatAvatar30)]
internal class MMDRelayPass : Pass<MMDRelayPass>
{
private const string MMDRelayParam = "__MA/Internal/MMDNotActive";
internal const string ControlLayerName = "Modular Avatar: MMD Control";
internal const string DummyLayerName = "Modular Avatar: MMD Dummy";
internal const string StateNameInitial = "Initial";
internal const string StateNameNotMMD = "NotMMD";
internal const string StateNameMMD = "MMD";
internal static bool ShouldRun(BuildContext context)
{
var settings = context.AvatarRootObject.GetComponentsInChildren<ModularAvatarVRChatSettings>(true);
return settings.FirstOrDefault()?.MMDWorldSupport ?? true;
}
protected override void Execute(BuildContext context)
{
if (!ShouldRun(context)) return;
var asc = context.Extension<AnimatorServicesContext>();
if (!asc.ControllerContext.Controllers.TryGetValue(VRCAvatarDescriptor.AnimLayerType.FX, out var fx))
return;
var affectedLayers = context.GetState<MMDRelayState>().mmdAffectedOriginalLayers;
foreach (var layer in fx.Layers)
{
if (layer.StateMachine == null) continue;
var rootMMDModeBehaviors = layer.StateMachine.Behaviours
.OfType<ModularAvatarMMDLayerControl>()
.ToList();
if (rootMMDModeBehaviors.Count == 0) continue;
if (rootMMDModeBehaviors.Count > 1)
{
ErrorReport.ReportError(Localization.L, ErrorSeverity.Error,
"error.mmd.multiple_mmd_mode_behaviors", layer.Name);
continue;
}
if (rootMMDModeBehaviors[0].DisableInMMDMode)
{
affectedLayers.Add(layer);
}
else
{
affectedLayers.Remove(layer);
}
layer.StateMachine.Behaviours = layer.StateMachine.Behaviours
.Where(b => b is not ModularAvatarMMDLayerControl).ToImmutableList();
Object.DestroyImmediate(rootMMDModeBehaviors[0]);
// check for child behaviors
// TODO: implement filtering on AllReachableNodes
foreach (var node in layer.AllReachableNodes())
{
if (node is VirtualState state)
{
if (state.Behaviours.Any(b => b is ModularAvatarMMDLayerControl))
{
ErrorReport.ReportError(Localization.L, ErrorSeverity.Error,
"error.mmd.mmd_mode_in_child_state", layer.Name, state.Name);
}
}
else if (node is VirtualStateMachine vsm)
{
if (vsm.Behaviours.Any(b => b is ModularAvatarMMDLayerControl))
{
ErrorReport.ReportError(Localization.L, ErrorSeverity.Error,
"error.mmd.mmd_mode_in_child_state_machine", layer.Name, vsm.Name);
}
}
}
}
var needsAdjustment = fx.Layers.Select((layer, index) => (layer, index))
.Any(pair => affectedLayers.Contains(pair.layer) != (pair.index < 3 && pair.index != 0));
if (!needsAdjustment) return;
var toDisable = fx.Layers.Where(l => affectedLayers.Contains(l))
.Select(l => l.VirtualLayerIndex)
.ToList();
fx.Parameters = fx.Parameters.Add(MMDRelayParam, new AnimatorControllerParameter
{
name = MMDRelayParam,
type = AnimatorControllerParameterType.Float,
defaultFloat = 0
});
var currentLayers = fx.Layers.ToList();
var newLayers = new List<VirtualLayer>();
// Layer zero's weight can't be changed anyway, so leave it where it is.
newLayers.Add(currentLayers[0]);
currentLayers.RemoveAt(0);
newLayers.Add(CreateMMDLayer(fx, toDisable));
// Add a dummy layer
var dummy = fx.AddLayer(new LayerPriority(0), DummyLayerName);
var s = dummy.StateMachine!.DefaultState = dummy.StateMachine.AddState("Dummy");
s.Motion = VirtualClip.Create("empty");
newLayers.Add(dummy);
fx.Layers = newLayers.Concat(currentLayers);
}
private static VirtualLayer CreateMMDLayer(VirtualAnimatorController fx, List<int> virtualLayers)
{
// We'll reorder this later, so the layer priority doesn't matter
var mmdControl = fx.AddLayer(new LayerPriority(0), ControlLayerName);
var stateMachine = mmdControl.StateMachine ?? throw new Exception("No state machine on MMD Control layer");
var motion = VirtualClip.Create("MMDRelay");
motion.SetFloatCurve(EditorCurveBinding.FloatCurve("", typeof(Animator), MMDRelayParam),
AnimationCurve.Constant(0, 1, 1)
);
var state_initial = stateMachine.AddState(StateNameInitial);
state_initial.Motion = motion;
var state_notmmd = stateMachine.AddState(StateNameNotMMD);
state_notmmd.Motion = motion;
var state_mmd = stateMachine.AddState(StateNameMMD);
state_mmd.Motion = motion;
var t = VirtualStateTransition.Create();
t.SetDestination(state_mmd);
t.Conditions = ImmutableList.Create(new AnimatorCondition
{
mode = AnimatorConditionMode.Less,
parameter = MMDRelayParam,
threshold = 0.5f
});
state_notmmd.Transitions = ImmutableList.Create(t);
t = VirtualStateTransition.Create();
t.SetDestination(state_notmmd);
t.Conditions = ImmutableList.Create(new AnimatorCondition
{
mode = AnimatorConditionMode.Greater,
parameter = MMDRelayParam,
threshold = 0.5f
});
state_mmd.Transitions = ImmutableList.Create(t);
t = VirtualStateTransition.Create();
t.SetDestination(state_mmd);
t.Conditions = ImmutableList.Create(new AnimatorCondition
{
mode = AnimatorConditionMode.Less,
parameter = MMDRelayParam,
threshold = 0.5f
});
state_initial.Transitions = ImmutableList.Create(t);
stateMachine.DefaultState = state_initial;
var mmd_behaviors = ImmutableList.CreateBuilder<StateMachineBehaviour>();
var notmmd_behaviors = ImmutableList.CreateBuilder<StateMachineBehaviour>();
foreach (var index in virtualLayers)
{
var behavior = ScriptableObject.CreateInstance<VRCAnimatorLayerControl>();
behavior.layer = index;
behavior.playable = VRC_AnimatorLayerControl.BlendableLayer.FX;
behavior.goalWeight = 0;
behavior.blendDuration = 0;
mmd_behaviors.Add(behavior);
behavior = ScriptableObject.CreateInstance<VRCAnimatorLayerControl>();
behavior.layer = index;
behavior.playable = VRC_AnimatorLayerControl.BlendableLayer.FX;
behavior.goalWeight = 1;
behavior.blendDuration = 0;
notmmd_behaviors.Add(behavior);
}
state_notmmd.Behaviours = notmmd_behaviors.ToImmutable();
state_mmd.Behaviours = mmd_behaviors.ToImmutable();
return mmdControl;
}
internal static bool IsRelayLayer(string layerName)
{
return layerName == ControlLayerName || layerName == DummyLayerName;
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 163fd3d0edea43d5969395079f561986
timeCreated: 1741745889

View File

@ -13,6 +13,7 @@ using UnityEngine;
namespace nadena.dev.modular_avatar.core.editor
{
[RunsOnPlatforms(WellKnownPlatforms.VRChatAvatar30)]
internal class ApplyAnimatorDefaultValuesPass : Pass<ApplyAnimatorDefaultValuesPass>
{
protected override void Execute(ndmf.BuildContext context)

View File

@ -6,7 +6,6 @@ using System.Collections.Immutable;
using System.Linq;
using UnityEditor;
using UnityEngine;
using UnityEngine.Experimental.Rendering;
using VRC.SDK3.Avatars.ScriptableObjects;
using Object = UnityEngine.Object;
@ -44,7 +43,7 @@ namespace nadena.dev.modular_avatar.core.editor
}
var parameters = context.AvatarDescriptor.expressionParameters.parameters
?? new VRCExpressionParameters.Parameter[0];
?? Array.Empty<VRCExpressionParameters.Parameter>();
var parameterNames = parameters.Select(p => p.name).ToImmutableHashSet();
if (!context.PluginBuildContext.IsTemporaryAsset(expressionsMenu))
@ -120,11 +119,20 @@ namespace nadena.dev.modular_avatar.core.editor
}
}
#if UNITY_ANDROID
private const TextureFormat TargetFormat = TextureFormat.ASTC_4x4;
#else
private const TextureFormat TargetFormat = TextureFormat.DXT5;
#endif
internal static TextureFormat TargetFormat
{
get
{
switch (EditorUserBuildSettings.activeBuildTarget)
{
case BuildTarget.StandaloneWindows64:
return TextureFormat.DXT5;
default:
return TextureFormat.ASTC_4x4;
}
}
}
private static Texture2D MaybeScaleIcon(BuildContext context, Texture2D original)
{
@ -133,10 +141,14 @@ namespace nadena.dev.modular_avatar.core.editor
return original;
}
var newRatio = Math.Min(256f / original.width, 256f / original.height);
var newRatio = Math.Min(1, Math.Min(256f / original.width, 256f / original.height));
var newWidth = Math.Min(256, Mathf.RoundToInt(original.width * newRatio));
var newHeight = Math.Min(256, Mathf.RoundToInt(original.height * newRatio));
// Round up to a multiple of four
newWidth = (newWidth + 3) & ~3;
newHeight = (newHeight + 3) & ~3;
var newTex = new Texture2D(newWidth, newHeight, TextureFormat.RGBA32, true);
context.SaveAsset(newTex);

View File

@ -0,0 +1,30 @@
using UnityEditor;
using static nadena.dev.modular_avatar.core.editor.Localization;
namespace nadena.dev.modular_avatar.core.editor
{
[CustomEditor(typeof(ModularAvatarMMDLayerControl))]
internal class MMDModeEditor : MAEditorBase
{
private SerializedProperty m_p_DisableInMMDMode;
private void OnEnable()
{
m_p_DisableInMMDMode =
serializedObject.FindProperty(nameof(ModularAvatarMMDLayerControl.m_DisableInMMDMode));
}
protected override void OnInnerInspectorGUI()
{
serializedObject.Update();
LogoDisplay.DisplayLogo();
EditorGUILayout.PropertyField(m_p_DisableInMMDMode, G("mmd_mode.disable_in_mmd_mode"));
ShowLanguageUI();
serializedObject.ApplyModifiedProperties();
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: a1a682db3a3b491fa27980adfeeacffd
timeCreated: 1741836147

View File

@ -1,4 +1,7 @@
#if MA_VRCSDK3_AVATARS
using System;
using System.Linq;
using System.Collections.Generic;
using nadena.dev.modular_avatar.ui;
using UnityEditor;
using UnityEngine;
@ -9,39 +12,170 @@ namespace nadena.dev.modular_avatar.core.editor
internal static class ToggleCreatorShortcut
{
[MenuItem(UnityMenuItems.GameObject_CreateToggleForSelection, false, UnityMenuItems.GameObject_CreateToggleForSelectionOrder)]
private static void CreateToggleForSelection(MenuCommand command) => CreateToggleImpl(command, true);
private static void CreateToggleForSelection()
{
var forSelection = true;
var selections = Selection.objects.OfType<GameObject>();
// Ignore GameObjects with submenu in the context of CreateToggleForSelection.
selections = selections.Where(s => !TryGetChildrenSourceSubmenu(s, out var _));
if (selections.Count() == 0) return;
// Grouping according to parent
var groups = new Dictionary<GameObject, HashSet<GameObject>>();
foreach (var selected in selections)
{
var parent = selected.transform.parent?.gameObject;
if (parent == null) continue;
if (!groups.ContainsKey(parent))
{
groups[parent] = new();
}
groups[parent].Add(selected);
}
foreach (var group in groups)
{
var parent = group.Key;
var targets = group.Value;
if (parent == null) continue;
if (targets == null || targets.Count() == 0) continue;
var avatarRoot = RuntimeUtil.FindAvatarTransformInParents(parent.transform);
if (avatarRoot == null) continue;
var subMenuName = parent.name + " Toggles";
// Try to find target submenu that should be the parent of toggles
ModularAvatarMenuItem targetSubMenu = null;
if (TryGetChildrenSourceSubmenu(parent, out var subMenu))
{
// If parent has subMenu, use it as target submenu.
targetSubMenu = subMenu;
}
else
{
// If parent hasn't subMenu, get submenus at the same level
var subMenus = new List<ModularAvatarMenuItem>();
foreach (Transform sibling in parent.transform)
{
if (TryGetChildrenSourceSubmenu(sibling.gameObject, out var m)) { subMenus.Add(m); }
}
// Filter to submenus with the same name
subMenus = subMenus.Where(m => m.gameObject.name == subMenuName).ToList();
// If only one submenu as target is found, use it as target submenu.
if (subMenus.Count() == 1) targetSubMenu = subMenus.First();
}
if (targetSubMenu != null) // If target SubMenu is found, add the toggles as children of it.
{
parent = targetSubMenu.gameObject;
CreateToggleImpl(targets, parent, forSelection, createInstaller:false);
}
else
{
if (targets.Count() > 1) // Create a submenu and add the toggles as children of it.
{
parent = CreateSubMenu(parent, subMenuName).gameObject;
CreateToggleImpl(targets, parent, forSelection, createInstaller:false);
}
else // Create a single toggle with installer.
{
var target = targets.First();
CreateToggleImpl(target, parent, forSelection, createInstaller:true);
}
}
}
Selection.objects = null;
}
[MenuItem(UnityMenuItems.GameObject_CreateToggle, false, UnityMenuItems.GameObject_CreateToggleOrder)]
private static void CreateToggle(MenuCommand command) => CreateToggleImpl(command, false);
private static void CreateToggleImpl(MenuCommand command, bool forSelection)
private static void CreateToggle()
{
var selected = command.context as GameObject;
if (selected == null) return;
var selections = Selection.objects.OfType<GameObject>();
if (selections.Count() == 0) return;
var avatarRoot = RuntimeUtil.FindAvatarTransformInParents(selected.transform);
if (avatarRoot == null) return;
foreach (var selected in selections)
{
var avatarRoot = RuntimeUtil.FindAvatarTransformInParents(selected.transform);
if (avatarRoot == null) return;
bool createInstaller = true;
Transform parent = avatarRoot;
var parent = avatarRoot.gameObject;
var createInstaller = true;
if (TryGetChildrenSourceSubmenu(selected, out var _))
{
parent = selected;
createInstaller = false;
}
CreateToggleImpl(selected, parent, createInstaller:createInstaller);
}
Selection.objects = null;
}
private static bool TryGetChildrenSourceSubmenu(GameObject target, out ModularAvatarMenuItem subMenu)
{
subMenu = null;
try
{
var selectedMenuItem = selected.GetComponent<ModularAvatarMenuItem>();
if (selectedMenuItem?.Control?.type == VRCExpressionsMenu.Control.ControlType.SubMenu
&& selectedMenuItem.MenuSource == SubmenuSource.Children
var mami = target.GetComponent<ModularAvatarMenuItem>();
if (mami?.Control?.type == VRCExpressionsMenu.Control.ControlType.SubMenu
&& mami.MenuSource == SubmenuSource.Children
)
{
parent = selected.transform;
createInstaller = false;
subMenu = mami;
return true;
}
}
catch (MissingComponentException)
{
// ignore
}
return false;
}
private static ModularAvatarMenuItem CreateSubMenu(GameObject parent, string submenuname)
{
var submenu = new GameObject(submenuname);
submenu.transform.SetParent(parent.transform);
var name = forSelection ? selected.name + " Toggle" : "New Toggle";
var mami = submenu.AddComponent<ModularAvatarMenuItem>();
mami.InitSettings();
mami.Control = new VRCExpressionsMenu.Control
{
type = VRCExpressionsMenu.Control.ControlType.SubMenu,
name = submenuname,
};
submenu.AddComponent<ModularAvatarMenuInstaller>();
Selection.activeGameObject = submenu;
EditorGUIUtility.PingObject(submenu);
Undo.RegisterCreatedObjectUndo(submenu, "Create SubMenu");
return mami;
}
private static void CreateToggleImpl(IEnumerable<GameObject> selections, GameObject parent, bool forSelection = false, bool createInstaller = true)
{
foreach (var selected in selections)
{
CreateToggleImpl(selected, parent, forSelection, createInstaller);
}
}
private static void CreateToggleImpl(GameObject selected, GameObject parent, bool forSelection = false, bool createInstaller = true)
{
var avatarRoot = RuntimeUtil.FindAvatarTransformInParents(selected.transform);
if (avatarRoot == null) return;
var suffix = selected.activeSelf ? "OFF" : "ON";
var name = forSelection ? $"{selected.name} {suffix}" : "New Toggle";
var toggle = new GameObject(name);
@ -57,7 +191,7 @@ namespace nadena.dev.modular_avatar.core.editor
}
toggle.transform.SetParent(parent, false);
toggle.transform.SetParent(parent.transform, false);
var mami = toggle.AddComponent<ModularAvatarMenuItem>();
mami.InitSettings();

View File

@ -11,6 +11,12 @@ namespace nadena.dev.modular_avatar.core.editor
protected override string localizationPrefix => "path_mode";
}
[CustomPropertyDrawer(typeof(MergeAnimatorMode))]
internal class MergeModeDrawer : EnumDrawer<MergeAnimatorMode>
{
protected override string localizationPrefix => "merge_animator.merge_mode";
}
[CustomEditor(typeof(ModularAvatarMergeAnimator))]
class MergeAnimationEditor : MAEditorBase
{
@ -20,7 +26,8 @@ namespace nadena.dev.modular_avatar.core.editor
prop_pathMode,
prop_matchAvatarWriteDefaults,
prop_relativePathRoot,
prop_layerPriority;
prop_layerPriority,
prop_mergeMode;
private void OnEnable()
{
@ -34,6 +41,7 @@ namespace nadena.dev.modular_avatar.core.editor
prop_relativePathRoot =
serializedObject.FindProperty(nameof(ModularAvatarMergeAnimator.relativePathRoot));
prop_layerPriority = serializedObject.FindProperty(nameof(ModularAvatarMergeAnimator.layerPriority));
prop_mergeMode = serializedObject.FindProperty(nameof(ModularAvatarMergeAnimator.mergeAnimatorMode));
}
protected override void OnInnerInspectorGUI()
@ -47,8 +55,12 @@ namespace nadena.dev.modular_avatar.core.editor
if (prop_pathMode.enumValueIndex == (int) MergeAnimatorPathMode.Relative)
EditorGUILayout.PropertyField(prop_relativePathRoot, G("merge_animator.relative_path_root"));
EditorGUILayout.PropertyField(prop_layerPriority, G("merge_animator.layer_priority"));
EditorGUILayout.PropertyField(prop_matchAvatarWriteDefaults,
G("merge_animator.match_avatar_write_defaults"));
EditorGUILayout.PropertyField(prop_mergeMode, G("merge_animator.merge_mode"));
using (new EditorGUI.DisabledScope(prop_mergeMode.enumValueIndex == (int)MergeAnimatorMode.Replace))
{
EditorGUILayout.PropertyField(prop_matchAvatarWriteDefaults,
G("merge_animator.match_avatar_write_defaults"));
}
serializedObject.ApplyModifiedProperties();

View File

@ -1,7 +1,7 @@
#if MA_VRCSDK3_AVATARS
using UnityEditor;
using UnityEditor.Animations;
using UnityEngine;
using static nadena.dev.modular_avatar.core.editor.Localization;
namespace nadena.dev.modular_avatar.core.editor
@ -15,7 +15,9 @@ namespace nadena.dev.modular_avatar.core.editor
private void OnEnable()
{
#pragma warning disable CS0618 // Type or member is obsolete
_blendTree = serializedObject.FindProperty(nameof(ModularAvatarMergeBlendTree.BlendTree));
#pragma warning restore CS0618 // Type or member is obsolete
_pathMode = serializedObject.FindProperty(nameof(ModularAvatarMergeBlendTree.PathMode));
_relativePathRoot = serializedObject.FindProperty(nameof(ModularAvatarMergeBlendTree.RelativePathRoot));
}
@ -24,7 +26,7 @@ namespace nadena.dev.modular_avatar.core.editor
{
serializedObject.Update();
EditorGUILayout.ObjectField(_blendTree, typeof(BlendTree), G("merge_blend_tree.blend_tree"));
EditorGUILayout.ObjectField(_blendTree, typeof(Motion), G("merge_blend_tree.motion"));
EditorGUILayout.PropertyField(_pathMode, G("merge_blend_tree.path_mode"));
if (_pathMode.enumValueIndex == (int) MergeAnimatorPathMode.Relative)
{

View File

@ -5,7 +5,6 @@ using System.Linq;
using UnityEditor;
using UnityEditor.UIElements;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.UIElements;
using VRC.SDK3.Avatars.ScriptableObjects;
using static nadena.dev.modular_avatar.core.editor.Localization;
@ -42,7 +41,7 @@ namespace nadena.dev.modular_avatar.core.editor
listView.selectionType = SelectionType.Multiple;
listView.RegisterCallback<KeyDownEvent>(evt =>
{
if (evt.keyCode == KeyCode.Delete)
if (evt.keyCode == KeyCode.Delete && evt.modifiers == EventModifiers.FunctionKey)
{
serializedObject.Update();
@ -66,9 +65,9 @@ namespace nadena.dev.modular_avatar.core.editor
listView.SetSelectionWithoutNotify(indices);
};
}
evt.StopPropagation();
}
evt.StopPropagation();
}, TrickleDown.NoTrickleDown);
unregisteredListView = root.Q<ListView>("UnregisteredParameters");

View File

@ -2,6 +2,7 @@
using System;
using UnityEditor;
using UnityEngine;
using UnityEngine.UIElements;
using Toggle = UnityEngine.UIElements.Toggle;
@ -83,8 +84,12 @@ namespace nadena.dev.modular_avatar.core.editor.Parameters
foreach (var elem in root.Query<TextElement>().Build())
{
// Prevent keypresses from bubbling up
elem.RegisterCallback<KeyDownEvent>(evt => evt.StopPropagation(), TrickleDown.NoTrickleDown);
// Prevent delete keypresses from bubbling up if we're in a text field
elem.RegisterCallback<KeyDownEvent>(evt =>
{
if (evt.keyCode == KeyCode.Delete && evt.modifiers == EventModifiers.FunctionKey)
evt.StopPropagation();
});
}
return root;

View File

@ -0,0 +1,12 @@
using UnityEditor;
namespace nadena.dev.modular_avatar.core.editor
{
[CustomEditor(typeof(ModularAvatarWorldScaleObject))]
internal class WorldScaleObjectEditor : MAEditorBase
{
protected override void OnInnerInspectorGUI()
{
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: e9b8b83586074bd7a6441b4cd7539dc9
timeCreated: 1741658287

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: d59587969bdd48f4ba16883ee3b30d4d
timeCreated: 1742695977

View File

@ -0,0 +1,27 @@
using UnityEditor;
namespace nadena.dev.modular_avatar.core.editor
{
[CustomEditor(typeof(ModularAvatarVRChatSettings))]
internal class VRChatSettingsEditor : MAEditorBase
{
protected override void OnInnerInspectorGUI()
{
serializedObject.Update();
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(
serializedObject.FindProperty(nameof(ModularAvatarVRChatSettings.m_mmdWorldSupport)),
Localization.G("platform.vrchat.settings.mmd_world_support")
);
if (EditorGUI.EndChangeCheck())
{
serializedObject.ApplyModifiedProperties();
}
Localization.ShowLanguageUI();
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 1ffd87033f4d441b849ad147b6e2a6ef
timeCreated: 1742695986

View File

@ -78,6 +78,9 @@
"merge_animator.relative_path_root.tooltip": "The root object to use when interpreting relative paths. If not specified, the object this component is attached to will be used.",
"merge_animator.layer_priority": "Layer Priority",
"merge_animator.layer_priority.tooltip": "Controls the order in which layers are merged into the animator - lower to higher. Negative values are merged before the original layer on the avatar descriptor, while zero and positive numbers are merged after.",
"merge_animator.merge_mode": "Merge Mode",
"merge_animator.merge_mode.Append": "Append to Animator",
"merge_animator.merge_mode.Replace": "Replace Existing Animator",
"merge_armature.lockmode": "Position sync mode",
"merge_armature.lockmode.not_locked.title": "Not locked",
"merge_armature.lockmode.not_locked.body": "Merged armature does not sync its position with the base avatar.",
@ -93,7 +96,7 @@
"merge_armature.reset_pos.execute": "Do it!",
"merge_armature.reset_pos.heuristic_scale": "Adjust outfit overall scale to match base avatar",
"merge_armature.reset_pos.heuristic_scale.tooltip": "Will set the overall scale of the outfit as a whole based on armspan measurements. Recommended for setting up outfits.",
"merge_blend_tree.blend_tree": "Blend Tree",
"merge_blend_tree.motion": "Motion (or Blend Tree) to merge",
"merge_blend_tree.path_mode": "Path Mode",
"merge_blend_tree.path_mode.tooltip": "How to interpret paths in animations. Using relative mode lets you record animations from an animator on this object.",
"merge_blend_tree.relative_path_root": "Relative Path Root",
@ -154,6 +157,8 @@
"error.replace_object.replacing_replacement": "[MA-0009] The same target object cannot be specified in multiple Replace Object components",
"error.replace_object.parent_of_target": "[MA-0010] The target object cannot be a parent of this object",
"error.singleton": "[MA-0011] Only one instance of {0} is allowed in an avatar",
"error.merge_animator.multiple_replacements": "[MA-0012] Multiple Merge Animators are trying to replace the same layer",
"error.merge_animator.multiple_replacements:hint": "Because the 'Replace' mode of Merge Animator replaces the entire animator with a different one, it's not clear which of these you wanted to have win. Try either deleting all but one of these Merge Animators, or setting them to Append mode.",
"validation.blendshape_sync.no_local_renderer": "[MA-1000] No renderer found on this object",
"validation.blendshape_sync.no_local_renderer:hint": "Blendshape Sync acts on a Skinned Mesh Renderer on the same GameObject. Did you attach it to the right object?",
"validation.blendshape_sync.no_local_mesh": "[MA-1001] No mesh found on the renderer on this object",
@ -299,6 +304,7 @@
"sync-param-sequence.parameters": "Common parameters asset",
"sync-param-sequence.parameters.tooltip": "The asset to store common parameters in. Do not use the same Expression Parameters that you have set in your avatar descriptor.",
"sync-param-sequence.create-asset": "New",
"sync-param-sequence.create-asset.tooltip": "Creates a new expression parameters asset"
"sync-param-sequence.create-asset.tooltip": "Creates a new expression parameters asset",
"platform.vrchat.settings.mmd_world_support": "MMD world support"
}

View File

@ -74,6 +74,9 @@
"merge_animator.relative_path_root.tooltip": "相対的パスはこのオブジェクトを基準に解釈されます。指定がない場合は、このコンポーネントがついているオブジェクトを基準とします。",
"merge_animator.layer_priority": "レイヤー統合優先度",
"merge_animator.layer_priority.tooltip": "アニメーターにレイヤーが統合される順番を制御します。低い値から高い値の順に統合されます。マイナスの場合は元々のAvatar Descriptorについているコントローラーより前に統合され、ゼロ以上の場合はそのあとに統合されます。",
"merge_animator.merge_mode": "統合モード",
"merge_animator.merge_mode.Append": "アニメーターに追加",
"merge_animator.merge_mode.Replace": "既存アニメーターを置き換える",
"merge_armature.lockmode": "位置追従モード",
"merge_armature.lockmode.not_locked.title": "追従なし",
"merge_armature.lockmode.not_locked.body": "統合されるアーマチュアは、統合先のアーマチュアに追従しません。",
@ -89,7 +92,7 @@
"merge_armature.reset_pos.execute": "実行",
"merge_armature.reset_pos.heuristic_scale": "衣装の全体的なスケールをアバターに合わせる",
"merge_armature.reset_pos.heuristic_scale.tooltip": "腕の長さを参考に、衣装全体のスケールをアバターに合わせます。非対応衣装を導入する時にお勧めです。",
"merge_blend_tree.blend_tree": "ブレンドツリー",
"merge_blend_tree.motion": "結合するモーション(またはブレンドツリー)",
"merge_blend_tree.path_mode": "パスモード",
"merge_blend_tree.path_mode.tooltip": "アニメーション内のパスを解釈するモード。相対的にすると、このオブジェクトにつけたアニメーターでアニメーションを編集することができます。",
"merge_blend_tree.relative_path_root": "相対的パスのルート",
@ -150,6 +153,8 @@
"error.replace_object.replacing_replacement": "[MA-0009] 複数のReplace Objectコンポーネントで、同じ置き換え先を指定できません",
"error.replace_object.parent_of_target": "[MA-0010] このオブジェクトの親を置き換え先に指定できません",
"error.singleton": "[MA-0011] {0} はアバターに一個しか存在できません",
"error.merge_animator.multiple_replacements": "[MA-0012] 複数のMerge Animatorが同じレイヤーを置き換えようとしています",
"error.merge_animator.multiple_replacements:hint": "Merge Animator の「既存アニメーターを置き換える」設定は丸ごと置き換えるので、複数があるとどれに置き換えたいかわかりません。一つを残してMerge Animatorを削除するか、一つを除いて「アニメーターに追加」にしてみましょう。",
"validation.blendshape_sync.no_local_renderer": "[MA-1000] このオブジェクトにはSkinned Mesh Rendererがありません。",
"validation.blendshape_sync.no_local_renderer:hint": "Blendshape Syncは同じGameObject上のSkinned Mesh Rendererに作用します。コンポーネントが正しいオブジェクトに追加されているか確認してください。",
"validation.blendshape_sync.no_local_mesh": "[MA-1001] このオブジェクトにはSkinned Mesh Rendererがありますが、メッシュがありません。",
@ -278,6 +283,8 @@
"ro_sim.effect_group.rule_inverted": "このルールの条件は反転されています",
"ro_sim.effect_group.rule_inverted.tooltip": "このルールは、いずれかの条件が満たされていない場合に適用されます",
"ro_sim.effect_group.conditions": "条件",
"menuitem.label.long_name.tooltip": "リッチテキスト、改行を含む長い名前にする。",
"menuitem.label.gameobject_name.tooltip": "ゲームオブジェクトの名前を採用する。",
"remove-vertex-color.mode": "モード",
"remove-vertex-color.mode.Remove": "頂点カラーを削除する",
"remove-vertex-color.mode.DontRemove": "頂点カラーを削除しない",
@ -287,5 +294,6 @@
"sync-param-sequence.parameters": "共用パラメーターアセット",
"sync-param-sequence.parameters.tooltip": "共用パラメーターがこのアセットに保持されます。アバターデスクリプターに使われるアセットを流用しないでください。",
"sync-param-sequence.create-asset": "新規作成",
"sync-param-sequence.create-asset.tooltip": "新しい共用パラメーターアセットを作成します"
"sync-param-sequence.create-asset.tooltip": "新しい共用パラメーターアセットを作成します",
"platform.vrchat.settings.mmd_world_support": "MMDワールド対応"
}

View File

@ -88,7 +88,6 @@
"merge_armature.reset_pos.execute": "실행",
"merge_armature.reset_pos.heuristic_scale": "의상의 전체적인 스케일을 원본 아바타에 맞춤",
"merge_armature.reset_pos.heuristic_scale.tooltip": "원본 아바타의 팔 길이를 참조하여, 의상의 전체 스케일을 이에 맞춥니다. 전용 의상이 아닌 경우 도움이 됩니다.",
"merge_blend_tree.blend_tree": "블랜드 트리",
"merge_blend_tree.path_mode": "경로 모드",
"merge_blend_tree.path_mode.tooltip": "애니메이션에서 경로를 해석하는 방법에 대해 설명합니다. 상대 모드를 사용하면 이 오브젝트의 애니메이터에서 애니메이션을 기록할 수 있습니다.",
"merge_blend_tree.relative_path_root": "상대적 경로",

View File

@ -93,7 +93,6 @@
"merge_armature.reset_pos.execute": "执行!",
"merge_armature.reset_pos.heuristic_scale": "根据 Avatar 调整服装的整体比例",
"merge_armature.reset_pos.heuristic_scale.tooltip": "以臂展作为参考,调整服装的整体比例。\n推荐用于不适配当前 Avatar 的服装。",
"merge_blend_tree.blend_tree": "BlendTree",
"merge_blend_tree.path_mode": "路径模式",
"merge_blend_tree.path_mode.tooltip": "在动画中路径的工作模式。\n使用相对路径可以让你在当前对象上录制动画。",
"merge_blend_tree.relative_path_root": "相对路径根对象",

View File

@ -93,7 +93,6 @@
"merge_armature.reset_pos.execute": "執行",
"merge_armature.reset_pos.heuristic_scale": "根據 Avatar 調整服裝的整體比例",
"merge_armature.reset_pos.heuristic_scale.tooltip": "以臂展作為參考,調整服裝的整體比例。\n推薦用於非 Avatar 對應的服裝。",
"merge_blend_tree.blend_tree": "Blend Tree",
"merge_blend_tree.path_mode": "路徑模式",
"merge_blend_tree.path_mode.tooltip": "在動畫中路徑的工作模式。\n使用相對路徑可以讓你在當前物件上錄制動畫。",
"merge_blend_tree.relative_path_root": "相對路徑根物件",

View File

@ -24,10 +24,13 @@
#if MA_VRCSDK3_AVATARS
using System;
using System.Collections.Generic;
using System.Linq;
using nadena.dev.modular_avatar.editor.ErrorReporting;
using nadena.dev.ndmf.animator;
using UnityEditor;
using UnityEditor.Animations;
using UnityEngine;
using VRC.SDK3.Avatars.Components;
using Object = UnityEngine.Object;
@ -86,30 +89,54 @@ namespace nadena.dev.modular_avatar.core.editor
List<ModularAvatarMergeAnimator> toMerge
)
{
// Stable sort
var sorted = toMerge.OrderBy(x => x.layerPriority)
.ToList();
var beforeOriginal = sorted.Where(x => x.layerPriority < 0)
.ToList();
var afterOriginal = sorted.Where(x => x.layerPriority >= 0)
// Layer priority sorting is handled by NDMF, so we just need to worry about replace mode going first
var sorted = toMerge.OrderBy(x => x.mergeAnimatorMode == MergeAnimatorMode.Append)
.ToList();
var controller = _asc.ControllerContext.Controllers[layerType];
var wdStateCounter = controller.Layers.SelectMany(l => l.StateMachine.AllStates())
.Select(s => s.WriteDefaultValues)
.GroupBy(b => b)
.ToDictionary(g => g.Key, g => g.Count());
bool? writeDefaults = null;
if (wdStateCounter.Count == 1) writeDefaults = wdStateCounter.First().Key;
var replacements = sorted.Count(x => x.mergeAnimatorMode == MergeAnimatorMode.Replace);
if (replacements > 1)
{
BuildReport.LogFatal("error.merge_animator.multiple_replacements",
sorted.Where(x => x.mergeAnimatorMode == MergeAnimatorMode.Replace).ToArray<object>());
}
else if (replacements == 1)
{
// Delete all pre-existing layers.
// Retain the blend tree layer, since that will generally be placed as the first layer in the animator
controller.RemoveLayers(l => l.Name != MergeBlendTreePass.BlendTreeLayerName);
// Merge just the first controller (the one that replaces)
MergeSingle(context, controller, sorted.First(), null);
sorted.RemoveAt(0);
// We'll now continue processing the rest as normal.
}
var writeDefaults = AnalyzeLayerWriteDefaults(controller);
foreach (var component in sorted)
{
MergeSingle(context, controller, component, writeDefaults);
}
}
internal static bool? AnalyzeLayerWriteDefaults(VirtualAnimatorController controller)
{
bool? writeDefaults = null;
var wdStateCounter = controller.Layers
.Where(l => !IsWriteDefaultsSafeLayer(l))
.SelectMany(l => l.StateMachine.AllStates())
.Select(s => s.WriteDefaultValues)
.GroupBy(b => b)
.ToDictionary(g => g.Key, g => g.Count());
if (wdStateCounter.Count == 1) writeDefaults = wdStateCounter.First().Key;
return writeDefaults;
}
private void MergeSingle(BuildContext context, VirtualAnimatorController targetController,
ModularAvatarMergeAnimator merge, bool? initialWriteDefaults)
{
@ -118,6 +145,11 @@ namespace nadena.dev.modular_avatar.core.editor
return;
}
if (!merge.matchAvatarWriteDefaults)
{
initialWriteDefaults = null;
}
var vac = context.PluginBuildContext.Extension<VirtualControllerContext>();
if (!vac.Controllers.TryGetValue(merge, out var clonedController)) return;
@ -128,14 +160,23 @@ namespace nadena.dev.modular_avatar.core.editor
foreach (var l in clonedController.Layers)
{
if (initialWriteDefaults != null)
if (initialWriteDefaults != null && !IsWriteDefaultsSafeLayer(l))
{
foreach (var s in l.StateMachine.AllStates())
foreach (var s in l.StateMachine?.AllStates() ?? Array.Empty<VirtualState>())
{
s.WriteDefaultValues = initialWriteDefaults.Value;
}
}
if (l.StateMachine?.DefaultState?.Motion is VirtualBlendTree
&& l.StateMachine.States.Count == 1
&& l.StateMachine.StateMachines.Count == 0
&& l.StateMachine.AnyStateTransitions.Count == 0)
{
// Force WD on for single state blendtree layers
l.StateMachine.DefaultState.WriteDefaultValues = true;
}
targetController.AddLayer(new LayerPriority(merge.layerPriority), l);
}
@ -174,6 +215,16 @@ namespace nadena.dev.modular_avatar.core.editor
Object.DestroyImmediate(merge);
}
private static bool IsWriteDefaultsSafeLayer(VirtualLayer virtualLayer)
{
if (virtualLayer.BlendingMode == AnimatorLayerBlendingMode.Additive) return true;
var sm = virtualLayer.StateMachine;
if (sm.StateMachines.Count != 0) return false;
return sm.States.Count == 1 && sm.AnyStateTransitions.Count == 0 &&
sm.DefaultState?.Transitions.Count == 0 && sm.DefaultState.Motion is VirtualBlendTree;
}
}
}

View File

@ -57,7 +57,7 @@ namespace nadena.dev.modular_avatar.core.editor
private AnimatorServicesContext AnimatorServices => frameworkContext.Extension<AnimatorServicesContext>();
private HashSet<Transform> humanoidBones = new HashSet<Transform>();
private HashSet<Transform> mergedObjects = new HashSet<Transform>();
private readonly HashSet<Transform> prunePBsObjects = new();
private HashSet<Transform> thisPassAdded = new HashSet<Transform>();
private HashSet<Transform> transformLookthrough = new HashSet<Transform>();
@ -279,7 +279,7 @@ namespace nadena.dev.modular_avatar.core.editor
BuildReport.ReportingObject(config, () =>
{
mergedObjects.Clear();
prunePBsObjects.Clear();
thisPassAdded.Clear();
MergeArmature(config, target);
#if MA_VRCSDK3_AVATARS
@ -366,7 +366,8 @@ namespace nadena.dev.modular_avatar.core.editor
private void RecursiveMerge(ModularAvatarMergeArmature config,
GameObject src,
GameObject newParent,
bool zipMerge)
bool zipMerge
)
{
if (src == newParent)
{
@ -376,10 +377,9 @@ namespace nadena.dev.modular_avatar.core.editor
if (zipMerge)
{
mergedObjects.Add(src.transform);
thisPassAdded.Add(src.transform);
}
bool retain = HasAdditionalComponents(src) || !zipMerge;
zipMerge = zipMerge && src.GetComponent<IConstraint>() == null;
@ -430,10 +430,26 @@ namespace nadena.dev.modular_avatar.core.editor
src.name = src.name + "$" + Guid.NewGuid();
}
src.GetOrAddComponent<ModularAvatarPBBlocker>();
mergedSrcBone = src;
if (zipMerge)
HashSet<Transform> childPhysBonesBlockedSet = null;
#if MA_VRCSDK3_AVATARS
src.GetOrAddComponent<ModularAvatarPBBlocker>();
if (physBoneByRootBone.TryGetValue(src.transform, out var pb)
&& !NotAffectedByPhysBoneOrSimilarChainsAsTarget(src.transform, newParent.transform))
{
childPhysBonesBlockedSet = new HashSet<Transform>(pb.ignoreTransforms);
}
else if (zipMerge)
{
prunePBsObjects.Add(src.transform);
}
#endif
// If we're zipping, and the current object is not being used for PBs, we can remove it later.
if (zipMerge && childPhysBonesBlockedSet == null)
{
transformLookthrough.Add(src.transform);
BoneDatabase.AddMergedBone(src.transform);
@ -447,6 +463,8 @@ namespace nadena.dev.modular_avatar.core.editor
if (zipMerge)
{
var reportedHumanoidBoneError = false;
foreach (Transform child in children)
{
if (child.GetComponent <ModularAvatarMergeArmature>() != null)
@ -466,20 +484,31 @@ namespace nadena.dev.modular_avatar.core.editor
var targetObjectName = childName.Substring(config.prefix.Length,
childName.Length - config.prefix.Length - config.suffix.Length);
var targetObject = newParent.transform.Find(targetObjectName);
if (childPhysBonesBlockedSet != null
&& !childPhysBonesBlockedSet.Contains(child)
&& !child.TryGetComponent<ModularAvatarPBBlocker>(out _))
{
// This object is potentially impacted by the parent's physbones; is it humanoid?
if (!reportedHumanoidBoneError && targetObject != null &&
humanoidBones.Contains(targetObject.transform))
{
// If so, fail the build, as we won't properly apply this to humanoid children.
BuildReport.LogFatal(
"error.merge_armature.physbone_on_humanoid_bone", new string[0], config);
reportedHumanoidBoneError = true;
}
// Don't move this child object
continue;
}
// Zip merge bones if the names match and the outfit side is not affected by its own PhysBone.
// Also zip merge when it seems to have been copied from avatar side by checking the dinstance.
if (targetObject != null)
{
if (NotAffectedByPhysBoneOrSimilarChainsAsTarget(child, targetObject))
{
childNewParent = targetObject.gameObject;
shouldZip = true;
}
else if (humanoidBones.Contains(targetObject))
{
BuildReport.LogFatal(
"error.merge_armature.physbone_on_humanoid_bone", new string[0], config);
}
childNewParent = targetObject.gameObject;
shouldZip = true;
}
}
@ -531,7 +560,7 @@ namespace nadena.dev.modular_avatar.core.editor
*/
private void PruneDuplicatePhysBones()
{
foreach (var obj in mergedObjects)
foreach (var obj in prunePBsObjects)
{
if (obj.GetComponent<VRCPhysBone>() == null) continue;
var baseObj = FindOriginalParent(obj);

View File

@ -2,6 +2,7 @@
#region
using System;
using System.Collections.Generic;
using nadena.dev.ndmf;
using nadena.dev.ndmf.animator;
@ -9,11 +10,13 @@ using UnityEditor;
using UnityEditor.Animations;
using UnityEngine;
using VRC.SDK3.Avatars.Components;
using Object = UnityEngine.Object;
#endregion
namespace nadena.dev.modular_avatar.core.editor
{
[RunsOnPlatforms(WellKnownPlatforms.VRChatAvatar30)]
internal class MergeBlendTreePass : Pass<MergeBlendTreePass>
{
internal const string ALWAYS_ONE = "__ModularAvatarInternal/One";
@ -62,14 +65,31 @@ namespace nadena.dev.modular_avatar.core.editor
foreach (var name in _parameterNames)
{
if (fx.Parameters.ContainsKey(name)) continue;
fx.Parameters = fx.Parameters.SetItem(name, new AnimatorControllerParameter()
if (fx.Parameters.TryGetValue(name, out var existingParameter))
{
name = name,
type = AnimatorControllerParameterType.Float,
defaultFloat = 0.0f
});
switch (existingParameter.type)
{
case AnimatorControllerParameterType.Bool:
existingParameter.defaultFloat = existingParameter.defaultBool ? 1 : 0;
break;
case AnimatorControllerParameterType.Int:
existingParameter.defaultFloat = existingParameter.defaultInt;
break;
}
existingParameter.type = AnimatorControllerParameterType.Float;
}
else
{
existingParameter = new AnimatorControllerParameter
{
name = name,
type = AnimatorControllerParameterType.Float,
defaultFloat = 0.0f
};
}
fx.Parameters = fx.Parameters.SetItem(name, existingParameter);
}
}
@ -83,8 +103,6 @@ namespace nadena.dev.modular_avatar.core.editor
return;
}
string basePath = null;
var rootBlend = GetRootBlendTree();
rootBlend.Children = rootBlend.Children.Add(new()
@ -136,6 +154,10 @@ namespace nadena.dev.modular_avatar.core.editor
var fx = _asc.ControllerContext.Controllers[VRCAvatarDescriptor.AnimLayerType.FX];
var controller = fx.AddLayer(new LayerPriority(int.MinValue), BlendTreeLayerName);
var stateMachine = controller.StateMachine;
if (fx == null)
{
throw new Exception("FX layer not found");
}
_rootBlendTree = VirtualBlendTree.Create("Root");
var state = stateMachine.AddState("State", _rootBlendTree);

View File

@ -89,8 +89,8 @@ namespace nadena.dev.modular_avatar.core.editor
public Task<IRenderFilterNode> Refresh(IEnumerable<(Renderer, Renderer)> proxyPairs, ComputeContext context,
RenderAspects updatedAspects)
{
if (updatedAspects.HasFlag(RenderAspects.Mesh)) return Task.FromResult<IRenderFilterNode>(null);
if (_theMesh == null) return Task.FromResult<IRenderFilterNode>(null);
if (updatedAspects.HasFlag(RenderAspects.Mesh)) return Task.FromResult<IRenderFilterNode>(null!);
if (_theMesh == null) return Task.FromResult<IRenderFilterNode>(null!);
return Task.FromResult<IRenderFilterNode>(this);
}

View File

@ -14,6 +14,7 @@ using VRC.Dynamics;
namespace nadena.dev.modular_avatar.core.editor
{
[RunsOnPlatforms(WellKnownPlatforms.VRChatAvatar30)]
internal class ConstraintConverterPass : Pass<ConstraintConverterPass>
{
#if MA_VRCSDK3_AVATARS_3_7_0_OR_NEWER
@ -52,13 +53,14 @@ namespace nadena.dev.modular_avatar.core.editor
var constraintGameObjects = context.AvatarRootObject.GetComponentsInChildren<IConstraint>(true)
.Select(c => (c as Component)?.gameObject)
.Where(go => go != null)
.Distinct()
.Where(go => go.GetComponentsInParent<ModularAvatarConvertConstraints>(true)
.Where(go => go!.GetComponentsInParent<ModularAvatarConvertConstraints>(true)
.Select(c => c.gameObject)
.Any(converters.Contains)
).ToArray();
var targetConstraintComponents =
constraintGameObjects.SelectMany(go => go.GetComponents<IConstraint>()).ToArray();
constraintGameObjects.SelectMany(go => go!.GetComponents<IConstraint>()).ToArray();
AvatarDynamicsSetup.DoConvertUnityConstraints(targetConstraintComponents, null, false);
@ -72,7 +74,7 @@ namespace nadena.dev.modular_avatar.core.editor
var targetPaths = constraintGameObjects
.Union(existingVRCConstraints)
.Select(c => asc.ObjectPathRemapper.GetVirtualPathForObject(c))
.Select(c => asc.ObjectPathRemapper.GetVirtualPathForObject(c!))
.ToHashSet();
// Update animation clips
@ -102,7 +104,7 @@ namespace nadena.dev.modular_avatar.core.editor
};
var curve = clip.GetFloatCurve(ecb);
clip.SetFloatCurve(newBinding, curve);
clip.SetFloatCurve(newBinding, null);
clip.SetFloatCurve(ecb, null);
}
}
}

View File

@ -5,6 +5,7 @@ using nadena.dev.ndmf;
namespace nadena.dev.modular_avatar.core.editor
{
[RunsOnPlatforms(WellKnownPlatforms.VRChatAvatar30)]
internal class PruneParametersPass : Pass<PruneParametersPass>
{
protected override void Execute(ndmf.BuildContext context)

View File

@ -156,7 +156,7 @@ namespace nadena.dev.modular_avatar.core.editor
case ModularAvatarMergeBlendTree mergeBlendTree:
{
WalkBlendTree(parameters, mergeBlendTree.BlendTree as BlendTree);
WalkBlendTree(parameters, mergeBlendTree.Motion as BlendTree);
break;
}

View File

@ -7,6 +7,7 @@ using nadena.dev.modular_avatar.editor.ErrorReporting;
using nadena.dev.ndmf;
using nadena.dev.ndmf.animator;
using nadena.dev.ndmf.fluent;
using nadena.dev.ndmf.model;
using nadena.dev.ndmf.util;
using UnityEngine;
using Object = UnityEngine.Object;
@ -19,6 +20,7 @@ using Object = UnityEngine.Object;
namespace nadena.dev.modular_avatar.core.editor.plugin
{
[RunsOnAllPlatforms]
class PluginDefinition : Plugin<PluginDefinition>
{
public override string QualifiedName => "nadena.dev.modular-avatar";
@ -38,22 +40,31 @@ namespace nadena.dev.modular_avatar.core.editor.plugin
Sequence seq = InPhase(BuildPhase.Resolving);
seq.Run(ResolveObjectReferences.Instance);
// Protect against accidental destructive edits by cloning the input controllers ASAP
seq.WithRequiredExtension(typeof(AnimatorServicesContext), s =>
{
// Just activating the context is enough.
s.Run("Clone animators", _ => { });
});
seq = InPhase(BuildPhase.Transforming);
seq.Run("Validate configuration",
context => ComponentValidation.ValidateAll(context.AvatarRootObject));
seq.WithRequiredExtension(typeof(ModularAvatarContext), _s1 =>
{
seq.Run(ClearEditorOnlyTags.Instance);
seq.Run(VRChatSettingsPass.Instance);
seq.Run(MeshSettingsPluginPass.Instance);
seq.Run(ScaleAdjusterPass.Instance).PreviewingWith(new ScaleAdjusterPreview());
// All these need to move to the new ASC
#if MA_VRCSDK3_AVATARS
seq.Run(ReactiveObjectPrepass.Instance);
#endif
seq.WithRequiredExtension(typeof(AnimatorServicesContext), _s2 =>
{
#if MA_VRCSDK3_AVATARS
seq.Run(MMDRelayEarlyPass.Instance);
seq.Run(RenameParametersPluginPass.Instance);
seq.Run(ParameterAssignerPass.Instance);
seq.Run(MergeBlendTreePass.Instance);
@ -62,7 +73,8 @@ namespace nadena.dev.modular_avatar.core.editor.plugin
seq.WithRequiredExtension(typeof(ReadablePropertyExtension), _s3 =>
{
seq.Run("Shape Changer", ctx => new ReactiveObjectPass(ctx).Execute())
// TODO - refactor out VRChat-specific bits
seq.Run("Reactive Components", ctx => new ReactiveObjectPass(ctx).Execute())
.PreviewingWith(new ShapeChangerPreview(), new ObjectSwitcherPreview(),
new MaterialSetterPreview());
});
@ -74,36 +86,43 @@ namespace nadena.dev.modular_avatar.core.editor.plugin
seq.Run(MenuInstallPluginPass.Instance);
#endif
seq.Run(MergeArmaturePluginPass.Instance);
seq.Run(BoneProxyPluginPass.Instance);
#if MA_VRCSDK3_AVATARS
seq.Run(VisibleHeadAccessoryPluginPass.Instance);
#endif
seq.Run("World Fixed Object",
ctx => new WorldFixedObjectProcessor().Process(ctx)
);
seq.OnPlatforms(new[] { WellKnownPlatforms.VRChatAvatar30 }, _seq =>
{
seq.Run("World Fixed Object",
ctx => new WorldFixedObjectProcessor().Process(ctx)
);
});
seq.Run(WorldScaleObjectPass.Instance);
seq.Run(ReplaceObjectPluginPass.Instance);
#if MA_VRCSDK3_AVATARS
seq.Run(BlendshapeSyncAnimationPluginPass.Instance);
seq.Run(ConstraintConverterPass.Instance);
#endif
seq.Run(ConstraintConverterPass.Instance);
seq.Run("Prune empty animator layers",
ctx => { ctx.Extension<AnimatorServicesContext>().RemoveEmptyLayers(); });
seq.Run("Harmonize animator parameter types",
ctx => { ctx.Extension<AnimatorServicesContext>().HarmonizeParameterTypes(); });
seq.Run(MMDRelayPass.Instance);
});
#if MA_VRCSDK3_AVATARS
seq.Run(PhysbonesBlockerPluginPass.Instance);
seq.Run("Fixup Expressions Menu", ctx =>
seq.OnPlatforms(new[] { WellKnownPlatforms.VRChatAvatar30 }, _seq =>
{
var maContext = ctx.Extension<ModularAvatarContext>().BuildContext;
FixupExpressionsMenuPass.FixupExpressionsMenu(maContext);
seq.Run("Fixup Expressions Menu", ctx =>
{
var maContext = ctx.Extension<ModularAvatarContext>().BuildContext;
FixupExpressionsMenuPass.FixupExpressionsMenu(maContext);
});
});
seq.Run(SyncParameterSequencePass.Instance);
#endif
@ -201,6 +220,7 @@ namespace nadena.dev.modular_avatar.core.editor.plugin
}
}
[RunsOnPlatforms(WellKnownPlatforms.VRChatAvatar30)]
class MergeAnimatorPluginPass : MAPass<MergeAnimatorPluginPass>
{
protected override void Execute(ndmf.BuildContext context)
@ -209,6 +229,7 @@ namespace nadena.dev.modular_avatar.core.editor.plugin
}
}
[RunsOnPlatforms(WellKnownPlatforms.VRChatAvatar30)]
class MenuInstallPluginPass : MAPass<MenuInstallPluginPass>
{
protected override void Execute(ndmf.BuildContext context)
@ -235,6 +256,7 @@ namespace nadena.dev.modular_avatar.core.editor.plugin
}
#if MA_VRCSDK3_AVATARS
[RunsOnPlatforms(WellKnownPlatforms.VRChatAvatar30)]
class VisibleHeadAccessoryPluginPass : MAPass<VisibleHeadAccessoryPluginPass>
{
protected override void Execute(ndmf.BuildContext context)
@ -253,6 +275,7 @@ namespace nadena.dev.modular_avatar.core.editor.plugin
}
#if MA_VRCSDK3_AVATARS
[RunsOnPlatforms(WellKnownPlatforms.VRChatAvatar30)] // TODO - support other platforms
class BlendshapeSyncAnimationPluginPass : MAPass<BlendshapeSyncAnimationPluginPass>
{
protected override void Execute(ndmf.BuildContext context)
@ -260,7 +283,7 @@ namespace nadena.dev.modular_avatar.core.editor.plugin
new BlendshapeSyncAnimationProcessor(context).OnPreprocessAvatar();
}
}
class PhysbonesBlockerPluginPass : MAPass<PhysbonesBlockerPluginPass>
{
protected override void Execute(ndmf.BuildContext context)

View File

@ -1,4 +1,6 @@
using System;
#nullable enable
using System;
using System.Collections.Generic;
using System.Linq;
using Object = UnityEngine.Object;
@ -14,6 +16,8 @@ namespace nadena.dev.modular_avatar.core.editor
// Objects which trigger deletion of this shape key.
public List<ReactionRule> actionGroups = new List<ReactionRule>();
public object? overrideStaticState = null;
public AnimatedProperty(TargetProp key, float currentState)
{
TargetProp = key;
@ -32,7 +36,7 @@ namespace nadena.dev.modular_avatar.core.editor
TargetProp.Equals(other.TargetProp);
}
public override bool Equals(object obj)
public override bool Equals(object? obj)
{
if (obj is null) return false;
if (ReferenceEquals(this, obj)) return true;

View File

@ -1,4 +1,5 @@
#if MA_VRCSDK3_AVATARS
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
@ -20,6 +21,9 @@ namespace nadena.dev.modular_avatar.core.editor
private readonly ndmf.BuildContext _context;
private readonly AnimatorServicesContext _asc;
private readonly ReadablePropertyExtension _rpe;
private static readonly ImmutableHashSet<Type> ActiveObjectTypes =
new[] { typeof(AudioSource) }.ToImmutableHashSet();
private Dictionary<string, float> _simulationInitialStates;
@ -115,6 +119,8 @@ namespace nadena.dev.modular_avatar.core.editor
FindObjectToggles(shapes, root);
FindMaterialSetters(shapes, root);
InjectActiveObjectFallbacks(shapes);
ApplyInitialStateOverrides(shapes);
AnalyzeConstants(shapes);
ResolveToggleInitialStates(shapes);
@ -124,6 +130,48 @@ namespace nadena.dev.modular_avatar.core.editor
return result;
}
private void InjectActiveObjectFallbacks(Dictionary<TargetProp, AnimatedProperty> shapes)
{
var injectedComponents = new List<Behaviour>();
foreach (var targetProp in shapes.Keys)
{
if (targetProp.TargetObject is GameObject go && targetProp.PropertyName == "m_IsActive")
{
foreach (var ty in ActiveObjectTypes)
{
foreach (var c in go.GetComponentsInChildren(ty, true))
{
if (c is Behaviour b)
{
injectedComponents.Add(b);
}
}
}
}
}
foreach (var component in injectedComponents)
{
var tp = new TargetProp
{
TargetObject = component,
PropertyName = "m_Enabled"
};
if (!shapes.TryGetValue(tp, out var shape))
{
var currentState = component.enabled ? 1f : 0f;
shape = new AnimatedProperty(tp, currentState);
// Because we have no action groups, we'll reset current state in the base animation and otherwise
// not touch the state.
shapes[tp] = shape;
}
shape.overrideStaticState = 0f; // Static state is always off
}
}
private void ApplyInitialStateOverrides(Dictionary<TargetProp, AnimatedProperty> shapes)
{
foreach (var prop in shapes.Values)
@ -182,9 +230,9 @@ namespace nadena.dev.modular_avatar.core.editor
group.actionGroups.RemoveRange(0, lastAlwaysOnGroup - 1);
}
// Remove shapes with no action groups
// Remove shapes with no action groups (unless we need to override static state)
foreach (var kvp in shapes.ToList())
if (kvp.Value.actionGroups.Count == 0)
if (kvp.Value.actionGroups.Count == 0 && kvp.Value.overrideStaticState == null)
shapes.Remove(kvp.Key);
}
@ -290,7 +338,7 @@ namespace nadena.dev.modular_avatar.core.editor
foreach (var (key, info) in shapes.ToList())
{
if (info.actionGroups.Count == 0)
if (info.actionGroups.Count == 0 && info.overrideStaticState == null)
{
// never active control; ignore it entirely
if (OptimizeShapes) shapes.Remove(key);
@ -305,9 +353,9 @@ namespace nadena.dev.modular_avatar.core.editor
initialStates[key] = initialState;
// If we're now constant-on, we can skip animation generation
if (info.actionGroups[^1].IsConstant)
if (info.actionGroups.Count == 0 || info.actionGroups[^1].IsConstant)
{
if (OptimizeShapes) shapes.Remove(key);
if (OptimizeShapes && info.overrideStaticState == null) shapes.Remove(key);
}
}
}

View File

@ -40,13 +40,11 @@ namespace nadena.dev.modular_avatar.core.editor
// Having a WD OFF layer after WD ON layers can break WD. We match the behavior of the existing states,
// and if mixed, use WD ON to maximize compatibility.
var asc = context.Extension<AnimatorServicesContext>();
_writeDefaults = asc.ControllerContext.Controllers[VRCAvatarDescriptor.AnimLayerType.FX]?.Layers.Any(
l => l.StateMachine.StateMachines.Any(
sm => sm.StateMachine.AllStates().Any(
s => s.WriteDefaultValues && s.Motion is not VirtualBlendTree
)
)
) ?? true;
var fxLayer = asc.ControllerContext.Controllers[VRCAvatarDescriptor.AnimLayerType.FX];
if (fxLayer != null)
{
_writeDefaults = MergeAnimatorProcessor.AnalyzeLayerWriteDefaults(fxLayer) ?? true;
}
var analysis = new ReactiveObjectAnalyzer(context).Analyze(context.AvatarRootObject);
@ -145,6 +143,11 @@ namespace nadena.dev.modular_avatar.core.editor
applied = true;
}
}
else if (key.TargetObject is Component c)
{
componentType = c.GetType();
path = RuntimeUtil.RelativePath(context.AvatarRootObject, c.gameObject);
}
else
{
throw new InvalidOperationException("Invalid target object: " + key.TargetObject);
@ -155,17 +158,19 @@ namespace nadena.dev.modular_avatar.core.editor
var serializedObject = new SerializedObject(key.TargetObject);
var prop = serializedObject.FindProperty(key.PropertyName);
var staticState = shapes.GetValueOrDefault(key)?.overrideStaticState ?? initialState;
if (prop != null)
{
switch (prop.propertyType)
{
case SerializedPropertyType.Boolean:
animBaseState = prop.boolValue ? 1.0f : 0.0f;
prop.boolValue = ((float)initialState) > 0.5f;
prop.boolValue = (float)staticState > 0.5f;
break;
case SerializedPropertyType.Float:
animBaseState = prop.floatValue;
prop.floatValue = (float) initialState;
prop.floatValue = (float)staticState;
break;
case SerializedPropertyType.ObjectReference:
animBaseState = prop.objectReferenceValue;
@ -309,6 +314,12 @@ namespace nadena.dev.modular_avatar.core.editor
private void ProcessShapeKey(AnimatedProperty info)
{
if (info.actionGroups.Count == 0)
{
// This is present only to override the static state; skip animation generation
return;
}
// TODO: prune non-animated keys
var asm = GenerateStateMachine(info);
ApplyController(asm, "MA Responsive: " + info.TargetProp.TargetObject.name);

View File

@ -9,6 +9,7 @@ namespace nadena.dev.modular_avatar.core.editor
/// Reserve an animator layer for reactive object use. We do this here so that we can take advantage of MergeAnimator's
/// layer reference correction logic; this can go away once we have a more unified animation services API.
/// </summary>
[RunsOnPlatforms(WellKnownPlatforms.VRChatAvatar30)]
internal class ReactiveObjectPrepass : Pass<ReactiveObjectPrepass>
{
internal const string TAG_PATH = "__MA/ShapeChanger/PrepassPlaceholder";
@ -49,7 +50,7 @@ namespace nadena.dev.modular_avatar.core.editor
var obj = new GameObject("MA SC Defaults");
obj.transform.SetParent(context.AvatarRootTransform);
var mambt = obj.AddComponent<ModularAvatarMergeBlendTree>();
mambt.BlendTree = bt;
mambt.Motion = bt;
mambt.PathMode = MergeAnimatorPathMode.Absolute;
}
}

View File

@ -54,6 +54,7 @@ namespace nadena.dev.modular_avatar.core.editor
if (!context.AvatarDescriptor) return;
var paramIndex = 0;
var mappings = ParameterRenameMappings.Get(context);
var declaredParams = context.AvatarDescriptor.expressionParameters.parameters
.GroupBy(p => p.name).Select(l => l.First())
@ -72,7 +73,8 @@ namespace nadena.dev.modular_avatar.core.editor
if (mami.Control == null) mami.Control = new VRCExpressionsMenu.Control();
mami.Control.parameter = new VRCExpressionsMenu.Control.Parameter
{
name = $"__MA/AutoParam/{mami.gameObject.name}${paramIndex++}"
name = mappings.Remap(mami, ParameterNamespace.Animator,
$"__MA/AutoParam/{mami.gameObject.name}")
};
}

View File

@ -6,6 +6,8 @@ using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using nadena.dev.modular_avatar.editor.ErrorReporting;
using nadena.dev.ndmf;
using nadena.dev.ndmf.animator;
@ -17,8 +19,6 @@ using VRC.SDK3.Dynamics.Contact.Components;
using VRC.SDK3.Dynamics.PhysBone.Components;
using Object = UnityEngine.Object;
using UnityObject = UnityEngine.Object;
#endregion
namespace nadena.dev.modular_avatar.core.editor
@ -30,18 +30,39 @@ namespace nadena.dev.modular_avatar.core.editor
return ctx.GetState<ParameterRenameMappings>();
}
public Dictionary<(ModularAvatarParameters, ParameterNamespace, string), string> Remappings =
new Dictionary<(ModularAvatarParameters, ParameterNamespace, string), string>();
private readonly HashSet<string> usedNames = new();
public Dictionary<(Component, ParameterNamespace, string), string> Remappings = new();
private int internalParamIndex;
public string Remap(ModularAvatarParameters p, ParameterNamespace ns, string s)
public string Remap(Component p, ParameterNamespace ns, string s)
{
var tuple = (p, ns, s);
if (Remappings.TryGetValue(tuple, out var mapping)) return mapping;
mapping = s + "$$Internal_" + internalParamIndex++;
var path = RuntimeUtil.AvatarRootPath(p.gameObject)!;
string pathHash;
using (var sha = SHA256.Create())
{
var hashBytes = sha.ComputeHash(Encoding.UTF8.GetBytes(path));
StringBuilder sb = new();
for (var i = 0; i < 6; i++)
{
sb.AppendFormat("{0:x2}", hashBytes[i]);
}
pathHash = sb.ToString();
}
mapping = s + "$" + pathHash;
for (var i = 0; !usedNames.Add(mapping); i++)
{
mapping = s + "$" + mapping + "." + i;
}
Remappings[tuple] = mapping;
return mapping;
@ -73,8 +94,8 @@ namespace nadena.dev.modular_avatar.core.editor
private static long encounterOrderCounter;
public ParameterConfig ResolvedParameter;
public List<UnityObject> TypeSources = new List<UnityObject>();
public List<UnityObject> DefaultSources = new List<UnityObject>();
public List<Object> TypeSources = new List<Object>();
public List<Object> DefaultSources = new List<Object>();
public ImmutableHashSet<float> ConflictingValues = ImmutableHashSet<float>.Empty;
public ImmutableHashSet<ParameterSyncType> ConflictingSyncTypes = ImmutableHashSet<ParameterSyncType>.Empty;
@ -174,7 +195,7 @@ namespace nadena.dev.modular_avatar.core.editor
// clean up all parameters objects before the ParameterAssignerPass runs
foreach (var p in avatar.GetComponentsInChildren<ModularAvatarParameters>())
UnityObject.DestroyImmediate(p);
Object.DestroyImmediate(p);
}
private void SetExpressionParameters(GameObject avatarRoot, ImmutableDictionary<string, ParameterInfo> allParams)
@ -366,7 +387,7 @@ namespace nadena.dev.modular_avatar.core.editor
break;
}
case IVirtualizeAnimatorController virtualized:
case IVirtualizeAnimatorController or IVirtualizeMotion:
{
var mappings = paramInfo.GetParameterRemappingsAt(obj);
var remap = mappings.SelectMany(item =>
@ -381,7 +402,7 @@ namespace nadena.dev.modular_avatar.core.editor
);
}).ToImmutableDictionary();
var controller = animServices.ControllerContext.Controllers[virtualized];
var controller = animServices.ControllerContext.Controllers[component];
if (controller != null)
{
ProcessVirtualAnimatorController(controller, remap);
@ -390,17 +411,6 @@ namespace nadena.dev.modular_avatar.core.editor
break;
}
case ModularAvatarMergeBlendTree merger:
{
var motion = animServices.ControllerContext.GetVirtualizedMotion(merger);
if (motion is VirtualBlendTree bt)
{
ProcessBlendtree(bt, paramInfo.GetParameterRemappingsAt(obj));
}
break;
}
case ModularAvatarMenuInstaller installer:
{
if (installer.menuToAppend != null && installer.enabled)

View File

@ -12,6 +12,7 @@ using Object = UnityEngine.Object;
namespace nadena.dev.modular_avatar.core.editor
{
[RunsOnPlatforms(WellKnownPlatforms.VRChatAvatar30)]
public class SyncParameterSequencePass : Pass<SyncParameterSequencePass>
{
private static Platform? CurrentPlatform

3
Editor/VRChat.meta Normal file
View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 476a3ae35e5046989e0c7276ae860e3c
timeCreated: 1742695540

View File

@ -0,0 +1,24 @@
using System.Collections.Generic;
using nadena.dev.modular_avatar.editor.ErrorReporting;
using nadena.dev.ndmf;
namespace nadena.dev.modular_avatar.core.editor
{
[RunsOnPlatforms(WellKnownPlatforms.VRChatAvatar30)]
internal class VRChatSettingsPass : Pass<VRChatSettingsPass>
{
protected override void Execute(ndmf.BuildContext context)
{
var settings = context.AvatarRootObject.GetComponentsInChildren<ModularAvatarVRChatSettings>(true);
if (settings.Length > 1)
{
var objects = new List<object>();
objects.Add("MA VRChat Settings");
objects.AddRange(settings);
BuildReport.LogFatal("error.singleton", objects);
}
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: cc7a69c0f9aa469dbcf8d4b492f5a6d9
timeCreated: 1742695552

View File

@ -1,9 +1,14 @@
using System.Linq;
using nadena.dev.modular_avatar.editor.ErrorReporting;
using nadena.dev.ndmf;
using UnityEditor;
using UnityEngine;
using VRC.Dynamics;
#if MA_VRCSDK3_AVATARS
using VRC.SDK3.Dynamics.Constraint.Components;
#else
using UnityEngine.Animations;
#endif
namespace nadena.dev.modular_avatar.core.editor
{
@ -31,17 +36,6 @@ namespace nadena.dev.modular_avatar.core.editor
void Process(ModularAvatarWorldFixedObject target)
{
switch (EditorUserBuildSettings.activeBuildTarget)
{
case BuildTarget.StandaloneWindows:
case BuildTarget.StandaloneWindows64:
case BuildTarget.StandaloneLinux64: // for CI
break;
default:
BuildReport.Log(ErrorSeverity.NonFatal, "world_fixed_object.err.unsupported_platform");
return;
}
var retargeter = new ActiveAnimationRetargeter(
_context,
new BoneDatabase(),
@ -86,7 +80,30 @@ namespace nadena.dev.modular_avatar.core.editor
obj.transform.localRotation = Quaternion.identity;
obj.transform.localScale = Vector3.one;
var constraint = obj.AddComponent<ParentConstraint>();
CreateConstraint(obj, fixedGameObject);
_proxy = obj.transform;
return obj.transform;
}
#if MA_VRCSDK3_AVATARS
private static void CreateConstraint(GameObject target, GameObject fixedGameObject)
{
var constraint = target.AddComponent<VRCParentConstraint>();
constraint.Sources.Add(new VRCConstraintSource
{
Weight = 1.0f,
SourceTransform = fixedGameObject.transform,
ParentRotationOffset = Vector3.zero,
ParentPositionOffset = Vector3.zero
});
constraint.IsActive = true;
constraint.Locked = true;
}
#else
private static void CreateConstraint(GameObject target, GameObject fixedGameObject)
{
var constraint = target.AddComponent<ParentConstraint>();
constraint.AddSource(new ConstraintSource()
{
weight = 1.0f,
@ -96,10 +113,7 @@ namespace nadena.dev.modular_avatar.core.editor
constraint.locked = true;
constraint.rotationOffsets = new[] {Vector3.zero};
constraint.translationOffsets = new[] {Vector3.zero};
_proxy = obj.transform;
return obj.transform;
}
#endif
}
}

View File

@ -0,0 +1,47 @@
using nadena.dev.modular_avatar.editor.ErrorReporting;
using nadena.dev.ndmf;
using UnityEditor;
using UnityEngine;
#if MA_VRCSDK3_AVATARS
using VRC.Dynamics;
using VRC.SDK3.Dynamics.Constraint.Components;
#else
using UnityEngine.Animations;
#endif
namespace nadena.dev.modular_avatar.core.editor
{
[RunsOnPlatforms(WellKnownPlatforms.VRChatAvatar30)]
internal class WorldScaleObjectPass : Pass<WorldScaleObjectPass>
{
protected override void Execute(ndmf.BuildContext context)
{
var fixedPrefab =
AssetDatabase.LoadAssetAtPath<GameObject>(
"Packages/nadena.dev.modular-avatar/Assets/FixedPrefab.prefab"
);
var targets = context.AvatarRootTransform.GetComponentsInChildren<ModularAvatarWorldScaleObject>(true);
foreach (var target in targets)
{
BuildReport.ReportingObject(target, () =>
{
#if MA_VRCSDK3_AVATARS
var c = target.gameObject.AddComponent<VRCScaleConstraint>();
c.Sources.Add(new VRCConstraintSource(fixedPrefab.transform, 1));
c.Locked = true;
c.IsActive = true;
#else
var c = target.gameObject.AddComponent<ScaleConstraint>();
c.AddSource(new ConstraintSource() {sourceTransform = fixedPrefab.transform, weight = 1});
c.locked = true;
c.constraintActive = true;
#endif
Object.DestroyImmediate(target);
});
}
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 19a3b07a9eeb413887792469f344c34d
timeCreated: 1741657804

View File

@ -29,7 +29,8 @@
"VRC.SDK3.Dynamics.Contact.Editor.dll",
"VRC.SDK3.Dynamics.PhysBone.dll",
"VRC.SDK3.Dynamics.PhysBone.Editor.dll",
"VRCCore-Editor.dll"
"VRCCore-Editor.dll",
"VRC.SDK3.Dynamics.Constraint.dll"
],
"autoReferenced": false,
"defineConstraints": [],

View File

@ -1,59 +0,0 @@
{
"name": "nadena.dev.modular-avatar.core.editor",
"rootNamespace": "",
"references": [
"nadena.dev.modular-avatar.core",
"VRC.SDK3A",
"VRC.SDKBase",
"nadena.dev.ndmf",
"nadena.dev.ndmf.vrchat",
"nadena.dev.ndmf.runtime",
"VRC.SDK3A.Editor",
"Unity.Burst"
],
"includePlatforms": [
"Editor"
],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": true,
"precompiledReferences": [
"Newtonsoft.Json.dll",
"System.Collections.Immutable.dll",
"VRCSDKBase.dll",
"VRCSDKBase-Editor.dll",
"VRCSDK3A.dll",
"VRCSDK3A-Editor.dll",
"VRC.Dynamics.dll",
"VRC.SDK3.Dynamics.Contact.dll",
"VRC.SDK3.Dynamics.Contact.Editor.dll",
"VRC.SDK3.Dynamics.PhysBone.dll",
"VRC.SDK3.Dynamics.PhysBone.Editor.dll",
"VRCCore-Editor.dll"
],
"autoReferenced": false,
"defineConstraints": [],
"versionDefines": [
{
"name": "com.anatawa12.avatar-optimizer",
"expression": "(,1.5.0-rc.8)",
"define": "LEGACY_AVATAR_OPTIMIZER"
},
{
"name": "com.vrchat.avatars",
"expression": "",
"define": "MA_VRCSDK3_AVATARS"
},
{
"name": "com.vrchat.avatars",
"expression": "3.5.2",
"define": "MA_VRCSDK3_AVATARS_3_5_2_OR_NEWER"
},
{
"name": "com.vrchat.avatars",
"expression": "3.7.0-beta.2",
"define": "MA_VRCSDK3_AVATARS_3_7_0_OR_NEWER"
}
],
"noEngineReferences": false
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 547 B

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

@ -16,8 +16,6 @@ namespace nadena.dev.modular_avatar.core
[HelpURL("https://modular-avatar.nadena.dev/docs/reference/move-independently?lang=auto")]
class MAMoveIndependently : MonoBehaviour, IEditorOnly
{
private float EPSILON = 0.0000001f;
[SerializeField]
private GameObject[] m_groupedBones;

View File

@ -0,0 +1,23 @@
using System.Diagnostics.CodeAnalysis;
using JetBrains.Annotations;
using UnityEngine;
namespace nadena.dev.modular_avatar.core
{
[AddComponentMenu("Modular Avatar/MA MMD Layer Control")]
[DisallowMultipleComponent]
[HelpURL("https://modular-avatar.nadena.dev/docs/reference/mmd-layer-control?lang=auto")]
[SuppressMessage("ReSharper", "InconsistentNaming")]
// ReSharper disable once RequiredBaseTypesIsNotInherited (false positive)
public sealed class ModularAvatarMMDLayerControl : StateMachineBehaviour
{
[SerializeField] internal bool m_DisableInMMDMode;
[PublicAPI]
public bool DisableInMMDMode
{
get => m_DisableInMMDMode;
set => m_DisableInMMDMode = value;
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: d1d979d3cedd4ddd969f414e2ea04fb8
timeCreated: 1741836107

View File

@ -37,6 +37,12 @@ namespace nadena.dev.modular_avatar.core
Absolute
}
public enum MergeAnimatorMode
{
Append,
Replace
}
[AddComponentMenu("Modular Avatar/MA Merge Animator")]
[HelpURL("https://modular-avatar.nadena.dev/docs/reference/merge-animator?lang=auto")]
public class ModularAvatarMergeAnimator : AvatarTagComponent, IVirtualizeAnimatorController
@ -51,7 +57,8 @@ namespace nadena.dev.modular_avatar.core
public bool matchAvatarWriteDefaults;
public AvatarObjectReference relativePathRoot = new AvatarObjectReference();
public int layerPriority = 0;
public MergeAnimatorMode mergeAnimatorMode = MergeAnimatorMode.Append;
public override void ResolveReferences()
{
// no-op
@ -78,7 +85,7 @@ namespace nadena.dev.modular_avatar.core
set => animator = value;
}
string IVirtualizeAnimatorController.GetMotionBasePath(object ndmfBuildContext, bool clearPath = true)
string IVirtualizeAnimatorController.GetMotionBasePath(object ndmfBuildContext, bool clearPath)
{
var path = GetMotionBasePathCallback(this, ndmfBuildContext);
if (clearPath) pathMode = MergeAnimatorPathMode.Absolute;

View File

@ -1,31 +1,51 @@
#if MA_VRCSDK3_AVATARS
using System;
using API;
using nadena.dev.ndmf.animator;
using JetBrains.Annotations;
using UnityEngine;
using Object = UnityEngine.Object;
namespace nadena.dev.modular_avatar.core
{
[AddComponentMenu("Modular Avatar/MA Merge Blend Tree")]
[AddComponentMenu("Modular Avatar/MA Merge Motion (Blend Tree)")]
[HelpURL("https://modular-avatar.nadena.dev/docs/reference/merge-blend-tree?lang=auto")]
public sealed class ModularAvatarMergeBlendTree : AvatarTagComponent, IVirtualizeMotion
{
internal static Func<ModularAvatarMergeBlendTree, object, string> GetMotionBasePathCallback
= (_, _) => "";
// We can't actually reference a BlendTree here because it's not available when building a player build
// Previous versions of this component expected a BlendTree, which is not available in player builds, so this
// field was made an Object. This can now become a Motion, but unfortunately that would be a breaking change.
/// <summary>
/// The blend tree or other motion to merge.
/// </summary>
[Obsolete("Use Motion property instead; this field will be removed in 2.0")] [PublicAPI]
public Object BlendTree;
[PublicAPI]
public MergeAnimatorPathMode PathMode = MergeAnimatorPathMode.Relative;
[PublicAPI]
public AvatarObjectReference RelativePathRoot = new AvatarObjectReference();
[PublicAPI]
public Motion Motion
{
get => ((IVirtualizeMotion)this).Motion;
set => ((IVirtualizeMotion)this).Motion = value;
}
Motion IVirtualizeMotion.Motion
{
#pragma warning disable CS0618 // Type or member is obsolete
get => (Motion)BlendTree;
set => BlendTree = value;
#pragma warning restore CS0618 // Type or member is obsolete
}
string IVirtualizeMotion.GetMotionBasePath(object ndmfBuildContext, bool clearPath = true)
string IVirtualizeMotion.GetMotionBasePath(object ndmfBuildContext, bool clearPath)
{
var path = GetMotionBasePathCallback(this, ndmfBuildContext);

View File

@ -0,0 +1,20 @@
using JetBrains.Annotations;
using UnityEngine;
namespace nadena.dev.modular_avatar.core
{
[AddComponentMenu("Modular Avatar/MA VRChat Settings")]
[DisallowMultipleComponent]
[HelpURL("https://modular-avatar.nadena.dev/docs/reference/vrchat-settings?lang=auto")]
public class ModularAvatarVRChatSettings : AvatarTagComponent
{
[SerializeField] internal bool m_mmdWorldSupport = true;
[PublicAPI]
public bool MMDWorldSupport
{
get => m_mmdWorldSupport;
set => m_mmdWorldSupport = value;
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 89c938d7d8a741df99f2eda501b3a6fe
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: a8edd5bd1a0a64a40aa99cc09fb5f198, type: 3}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,12 @@
using UnityEngine;
namespace nadena.dev.modular_avatar.core
{
[AddComponentMenu("Modular Avatar/MA World Scale Object")]
[DisallowMultipleComponent]
[HelpURL("https://modular-avatar.nadena.dev/docs/reference/world-scale-object?lang=auto")]
public class ModularAvatarWorldScaleObject : AvatarTagComponent
{
// no configuration
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e113c01563a14226b5e863befe6fe769
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: a8edd5bd1a0a64a40aa99cc09fb5f198, type: 3}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -3,6 +3,7 @@
using System.Collections;
using System.Collections.Generic;
using modular_avatar_tests;
using nadena.dev.modular_avatar.animation;
using nadena.dev.modular_avatar.core.editor;
using NUnit.Framework;
using UnityEditor.Animations;
@ -21,10 +22,12 @@ namespace modular_avatar_tests
var fxController = (AnimatorController) FindController(prefab, VRCAvatarDescriptor.AnimLayerType.FX).animatorController;
var l0 = fxController.layers[0];
var l1 = fxController.layers[1];
var l2 = fxController.layers[2];
var l3 = fxController.layers[3];
var l3a = fxController.layers[4];
Assert.AreEqual(MMDRelayPass.ControlLayerName, fxController.layers[1].name);
Assert.AreEqual(MMDRelayPass.DummyLayerName, fxController.layers[2].name);
var l1 = fxController.layers[3];
var l2 = fxController.layers[4];
var l3 = fxController.layers[5];
var l3a = fxController.layers[6];
Assert.AreEqual("Base Layer", l0.name);
Assert.AreEqual("L1", l1.name);
@ -37,10 +40,10 @@ namespace modular_avatar_tests
Assert.AreEqual("2", ((VRCAnimatorLayerControl)l3.stateMachine.defaultState.behaviours[0]).debugString);
Assert.IsTrue(l3.stateMachine.defaultState.behaviours[1] is VRCAnimatorTrackingControl);
Assert.AreEqual("3", ((VRCAnimatorLayerControl)l3.stateMachine.defaultState.behaviours[2]).debugString);
Assert.AreEqual(3, ((VRCAnimatorLayerControl)l3.stateMachine.defaultState.behaviours[0]).layer);
Assert.AreEqual(FindFxLayerIndex(prefab, l3), ((VRCAnimatorLayerControl)l3.stateMachine.defaultState.behaviours[0]).layer);
Assert.AreEqual(1, l3a.stateMachine.defaultState.behaviours.Length);
Assert.AreEqual(3, ((VRCAnimatorLayerControl)l3a.stateMachine.defaultState.behaviours[0]).layer);
Assert.AreEqual(FindFxLayerIndex(prefab, l3), ((VRCAnimatorLayerControl)l3a.stateMachine.defaultState.behaviours[0]).layer);
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 046888971cba42e895a515d3d07b955b
timeCreated: 1742001943

View File

@ -0,0 +1,192 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1102 &-7355338869790508137
AnimatorState:
serializedVersion: 6
m_ObjectHideFlags: 1
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: empty
m_Speed: 1
m_CycleOffset: 0
m_Transitions: []
m_StateMachineBehaviours: []
m_Position: {x: 50, y: 50, z: 0}
m_IKOnFeet: 0
m_WriteDefaultValues: 1
m_Mirror: 0
m_SpeedParameterActive: 0
m_MirrorParameterActive: 0
m_CycleOffsetParameterActive: 0
m_TimeParameterActive: 0
m_Motion: {fileID: 7400000, guid: 931318d79958463468b9ca3d48c96186, type: 2}
m_Tag:
m_SpeedParameter:
m_MirrorParameter:
m_CycleOffsetParameter:
m_TimeParameter:
--- !u!1107 &-3477861051435458144
AnimatorStateMachine:
serializedVersion: 6
m_ObjectHideFlags: 1
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: L0
m_ChildStates:
- serializedVersion: 1
m_State: {fileID: -7355338869790508137}
m_Position: {x: 441.0094, y: 127.91522, z: 0}
m_ChildStateMachines: []
m_AnyStateTransitions: []
m_EntryTransitions: []
m_StateMachineTransitions: {}
m_StateMachineBehaviours: []
m_AnyStatePosition: {x: 50, y: 20, z: 0}
m_EntryPosition: {x: 50, y: 120, z: 0}
m_ExitPosition: {x: 800, y: 120, z: 0}
m_ParentStateMachinePosition: {x: 800, y: 20, z: 0}
m_DefaultState: {fileID: -7355338869790508137}
--- !u!1107 &-3163258767259997666
AnimatorStateMachine:
serializedVersion: 6
m_ObjectHideFlags: 1
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: L2
m_ChildStates:
- serializedVersion: 1
m_State: {fileID: 2165750007709086016}
m_Position: {x: 320, y: 130, z: 0}
m_ChildStateMachines: []
m_AnyStateTransitions: []
m_EntryTransitions: []
m_StateMachineTransitions: {}
m_StateMachineBehaviours: []
m_AnyStatePosition: {x: 50, y: 20, z: 0}
m_EntryPosition: {x: 50, y: 120, z: 0}
m_ExitPosition: {x: 800, y: 120, z: 0}
m_ParentStateMachinePosition: {x: 800, y: 20, z: 0}
m_DefaultState: {fileID: 2165750007709086016}
--- !u!91 &9100000
AnimatorController:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: AC1
serializedVersion: 5
m_AnimatorParameters: []
m_AnimatorLayers:
- serializedVersion: 5
m_Name: L0
m_StateMachine: {fileID: -3477861051435458144}
m_Mask: {fileID: 0}
m_Motions: []
m_Behaviours: []
m_BlendingMode: 0
m_SyncedLayerIndex: -1
m_DefaultWeight: 0
m_IKPass: 0
m_SyncedLayerAffectsTiming: 0
m_Controller: {fileID: 9100000}
- serializedVersion: 5
m_Name: L1
m_StateMachine: {fileID: 3734055781436131242}
m_Mask: {fileID: 0}
m_Motions: []
m_Behaviours: []
m_BlendingMode: 0
m_SyncedLayerIndex: -1
m_DefaultWeight: 1
m_IKPass: 0
m_SyncedLayerAffectsTiming: 0
m_Controller: {fileID: 9100000}
- serializedVersion: 5
m_Name: L2
m_StateMachine: {fileID: -3163258767259997666}
m_Mask: {fileID: 0}
m_Motions: []
m_Behaviours: []
m_BlendingMode: 0
m_SyncedLayerIndex: -1
m_DefaultWeight: 1
m_IKPass: 0
m_SyncedLayerAffectsTiming: 0
m_Controller: {fileID: 9100000}
--- !u!1102 &2165750007709086016
AnimatorState:
serializedVersion: 6
m_ObjectHideFlags: 1
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: empty
m_Speed: 1
m_CycleOffset: 0
m_Transitions: []
m_StateMachineBehaviours: []
m_Position: {x: 50, y: 50, z: 0}
m_IKOnFeet: 0
m_WriteDefaultValues: 1
m_Mirror: 0
m_SpeedParameterActive: 0
m_MirrorParameterActive: 0
m_CycleOffsetParameterActive: 0
m_TimeParameterActive: 0
m_Motion: {fileID: 7400000, guid: 931318d79958463468b9ca3d48c96186, type: 2}
m_Tag:
m_SpeedParameter:
m_MirrorParameter:
m_CycleOffsetParameter:
m_TimeParameter:
--- !u!1102 &3470771388114793831
AnimatorState:
serializedVersion: 6
m_ObjectHideFlags: 1
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: empty
m_Speed: 1
m_CycleOffset: 0
m_Transitions: []
m_StateMachineBehaviours: []
m_Position: {x: 50, y: 50, z: 0}
m_IKOnFeet: 0
m_WriteDefaultValues: 1
m_Mirror: 0
m_SpeedParameterActive: 0
m_MirrorParameterActive: 0
m_CycleOffsetParameterActive: 0
m_TimeParameterActive: 0
m_Motion: {fileID: 7400000, guid: 931318d79958463468b9ca3d48c96186, type: 2}
m_Tag:
m_SpeedParameter:
m_MirrorParameter:
m_CycleOffsetParameter:
m_TimeParameter:
--- !u!1107 &3734055781436131242
AnimatorStateMachine:
serializedVersion: 6
m_ObjectHideFlags: 1
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: L1
m_ChildStates:
- serializedVersion: 1
m_State: {fileID: 3470771388114793831}
m_Position: {x: 495.48987, y: 46.194702, z: 0}
m_ChildStateMachines: []
m_AnyStateTransitions: []
m_EntryTransitions: []
m_StateMachineTransitions: {}
m_StateMachineBehaviours: []
m_AnyStatePosition: {x: 50, y: 20, z: 0}
m_EntryPosition: {x: 50, y: 120, z: 0}
m_ExitPosition: {x: 800, y: 120, z: 0}
m_ParentStateMachinePosition: {x: 800, y: 20, z: 0}
m_DefaultState: {fileID: 3470771388114793831}

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: e7f6321e9d2601a45a3efa0a24305b78
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 9100000
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,192 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1102 &-7355338869790508137
AnimatorState:
serializedVersion: 6
m_ObjectHideFlags: 1
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: empty
m_Speed: 1
m_CycleOffset: 0
m_Transitions: []
m_StateMachineBehaviours: []
m_Position: {x: 50, y: 50, z: 0}
m_IKOnFeet: 0
m_WriteDefaultValues: 1
m_Mirror: 0
m_SpeedParameterActive: 0
m_MirrorParameterActive: 0
m_CycleOffsetParameterActive: 0
m_TimeParameterActive: 0
m_Motion: {fileID: 7400000, guid: 931318d79958463468b9ca3d48c96186, type: 2}
m_Tag:
m_SpeedParameter:
m_MirrorParameter:
m_CycleOffsetParameter:
m_TimeParameter:
--- !u!1107 &-3477861051435458144
AnimatorStateMachine:
serializedVersion: 6
m_ObjectHideFlags: 1
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: M0
m_ChildStates:
- serializedVersion: 1
m_State: {fileID: -7355338869790508137}
m_Position: {x: 441.0094, y: 127.91522, z: 0}
m_ChildStateMachines: []
m_AnyStateTransitions: []
m_EntryTransitions: []
m_StateMachineTransitions: {}
m_StateMachineBehaviours: []
m_AnyStatePosition: {x: 50, y: 20, z: 0}
m_EntryPosition: {x: 50, y: 120, z: 0}
m_ExitPosition: {x: 800, y: 120, z: 0}
m_ParentStateMachinePosition: {x: 800, y: 20, z: 0}
m_DefaultState: {fileID: -7355338869790508137}
--- !u!1107 &-3163258767259997666
AnimatorStateMachine:
serializedVersion: 6
m_ObjectHideFlags: 1
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: M2
m_ChildStates:
- serializedVersion: 1
m_State: {fileID: 2165750007709086016}
m_Position: {x: 320, y: 130, z: 0}
m_ChildStateMachines: []
m_AnyStateTransitions: []
m_EntryTransitions: []
m_StateMachineTransitions: {}
m_StateMachineBehaviours: []
m_AnyStatePosition: {x: 50, y: 20, z: 0}
m_EntryPosition: {x: 50, y: 120, z: 0}
m_ExitPosition: {x: 800, y: 120, z: 0}
m_ParentStateMachinePosition: {x: 800, y: 20, z: 0}
m_DefaultState: {fileID: 2165750007709086016}
--- !u!91 &9100000
AnimatorController:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: AC2
serializedVersion: 5
m_AnimatorParameters: []
m_AnimatorLayers:
- serializedVersion: 5
m_Name: M0
m_StateMachine: {fileID: -3477861051435458144}
m_Mask: {fileID: 0}
m_Motions: []
m_Behaviours: []
m_BlendingMode: 0
m_SyncedLayerIndex: -1
m_DefaultWeight: 0
m_IKPass: 0
m_SyncedLayerAffectsTiming: 0
m_Controller: {fileID: 9100000}
- serializedVersion: 5
m_Name: M1
m_StateMachine: {fileID: 3734055781436131242}
m_Mask: {fileID: 0}
m_Motions: []
m_Behaviours: []
m_BlendingMode: 0
m_SyncedLayerIndex: -1
m_DefaultWeight: 1
m_IKPass: 0
m_SyncedLayerAffectsTiming: 0
m_Controller: {fileID: 9100000}
- serializedVersion: 5
m_Name: M2
m_StateMachine: {fileID: -3163258767259997666}
m_Mask: {fileID: 0}
m_Motions: []
m_Behaviours: []
m_BlendingMode: 0
m_SyncedLayerIndex: -1
m_DefaultWeight: 1
m_IKPass: 0
m_SyncedLayerAffectsTiming: 0
m_Controller: {fileID: 9100000}
--- !u!1102 &2165750007709086016
AnimatorState:
serializedVersion: 6
m_ObjectHideFlags: 1
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: empty
m_Speed: 1
m_CycleOffset: 0
m_Transitions: []
m_StateMachineBehaviours: []
m_Position: {x: 50, y: 50, z: 0}
m_IKOnFeet: 0
m_WriteDefaultValues: 1
m_Mirror: 0
m_SpeedParameterActive: 0
m_MirrorParameterActive: 0
m_CycleOffsetParameterActive: 0
m_TimeParameterActive: 0
m_Motion: {fileID: 7400000, guid: 931318d79958463468b9ca3d48c96186, type: 2}
m_Tag:
m_SpeedParameter:
m_MirrorParameter:
m_CycleOffsetParameter:
m_TimeParameter:
--- !u!1102 &3470771388114793831
AnimatorState:
serializedVersion: 6
m_ObjectHideFlags: 1
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: empty
m_Speed: 1
m_CycleOffset: 0
m_Transitions: []
m_StateMachineBehaviours: []
m_Position: {x: 50, y: 50, z: 0}
m_IKOnFeet: 0
m_WriteDefaultValues: 1
m_Mirror: 0
m_SpeedParameterActive: 0
m_MirrorParameterActive: 0
m_CycleOffsetParameterActive: 0
m_TimeParameterActive: 0
m_Motion: {fileID: 7400000, guid: 931318d79958463468b9ca3d48c96186, type: 2}
m_Tag:
m_SpeedParameter:
m_MirrorParameter:
m_CycleOffsetParameter:
m_TimeParameter:
--- !u!1107 &3734055781436131242
AnimatorStateMachine:
serializedVersion: 6
m_ObjectHideFlags: 1
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: M1
m_ChildStates:
- serializedVersion: 1
m_State: {fileID: 3470771388114793831}
m_Position: {x: 495.48987, y: 46.194702, z: 0}
m_ChildStateMachines: []
m_AnyStateTransitions: []
m_EntryTransitions: []
m_StateMachineTransitions: {}
m_StateMachineBehaviours: []
m_AnyStatePosition: {x: 50, y: 20, z: 0}
m_EntryPosition: {x: 50, y: 120, z: 0}
m_ExitPosition: {x: 800, y: 120, z: 0}
m_ParentStateMachinePosition: {x: 800, y: 20, z: 0}
m_DefaultState: {fileID: 3470771388114793831}

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: bf8dbf58ea7a7544cb5c7f86b790d0ff
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 9100000
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,138 @@
using System.Collections.Generic;
using nadena.dev.modular_avatar.animation;
using nadena.dev.modular_avatar.core.editor;
using NUnit.Framework;
using UnityEditor.Animations;
using UnityEngine.Assertions.Must;
using VRC.SDK3.Avatars.Components;
using VRC.SDKBase;
namespace modular_avatar_tests.MMD
{
public class MMDHandlingTests : TestBase
{
[Test]
public void MMDMode_NoopHandling()
{
var prefab = CreatePrefab("MMDMode_Noop.prefab");
AvatarProcessor.ProcessAvatar(prefab);
var fx = FindFxController(prefab);
var fxc = (AnimatorController)fx.animatorController;
Assert.AreEqual(3, fxc.layers.Length);
Assert.AreEqual("L0", fxc.layers[0].name);
Assert.AreEqual("L1", fxc.layers[1].name);
Assert.AreEqual("L2", fxc.layers[2].name);
}
[Test]
public void MMDMode_ReactiveComponent()
{
var prefab = CreatePrefab("MMDMode_Reactive.prefab");
AvatarProcessor.ProcessAvatar(prefab);
var fx = FindFxController(prefab);
var fxc = (AnimatorController)fx.animatorController;
// RC, MMD, dummy, L0, L1, L2
AssertMMDModeHandling(fxc, 4, 5);
Assert.AreEqual(MergeBlendTreePass.BlendTreeLayerName, fxc.layers[0].name);
Assert.AreEqual(MMDRelayPass.ControlLayerName, fxc.layers[1].name);
Assert.AreEqual(MMDRelayPass.DummyLayerName, fxc.layers[2].name);
Assert.AreEqual("L0", fxc.layers[3].name);
Assert.AreEqual("L1", fxc.layers[4].name);
Assert.AreEqual("L2", fxc.layers[5].name);
}
[Test]
public void MMDMode_MergeBefore()
{
var prefab = CreatePrefab("MMDMode_MergeBefore.prefab");
AvatarProcessor.ProcessAvatar(prefab);
var fx = FindFxController(prefab);
var fxc = (AnimatorController)fx.animatorController;
// M0, MMD, dummy, M1, M2, L0, L1, L2
AssertMMDModeHandling(fxc, 6, 7);
Assert.AreEqual(8, fxc.layers.Length);
Assert.AreEqual("M0", fxc.layers[0].name);
Assert.AreEqual(MMDRelayPass.ControlLayerName, fxc.layers[1].name);
Assert.AreEqual(MMDRelayPass.DummyLayerName, fxc.layers[2].name);
Assert.AreEqual("M1", fxc.layers[3].name);
Assert.AreEqual("M2", fxc.layers[4].name);
Assert.AreEqual("L0", fxc.layers[5].name);
Assert.AreEqual("L1", fxc.layers[6].name);
Assert.AreEqual("L2", fxc.layers[7].name);
}
[Test]
public void MMDMode_ManualOverride()
{
var prefab = CreatePrefab("MMDMode_Overrides.prefab");
AvatarProcessor.ProcessAvatar(prefab);
var fx = FindFxController(prefab);
var fxc = (AnimatorController)fx.animatorController;
// Base, MMD, dummy, ForceOff, DefaultOn, DefaultOff, ForceOn
AssertMMDModeHandling(fxc, 4, 6);
}
private void AssertMMDModeHandling(AnimatorController fxc, params int[] layers)
{
Assert.AreEqual(MMDRelayPass.ControlLayerName, fxc.layers[1].name);
Assert.AreEqual(MMDRelayPass.DummyLayerName, fxc.layers[2].name);
var expectedLayers = new HashSet<int>(layers);
foreach (var state in fxc.layers[1].stateMachine.states)
{
var actualLayers = new HashSet<int>();
float expectedWeight = -1f;
var behaviors = state.state.behaviours;
switch (state.state.name)
{
case MMDRelayPass.StateNameInitial:
Assert.IsEmpty(behaviors);
Assert.AreEqual(fxc.layers[1].stateMachine.defaultState, state.state);
continue;
case MMDRelayPass.StateNameNotMMD:
expectedWeight = 1f;
break;
case MMDRelayPass.StateNameMMD:
expectedWeight = 0f;
break;
default:
Assert.Fail($"Unexpected state {state.state.name}");
break;
}
foreach (var behavior in state.state.behaviours)
{
if (behavior is VRCAnimatorLayerControl lc)
{
Assert.AreEqual(expectedWeight, lc.goalWeight);
Assert.AreEqual(VRC_AnimatorLayerControl.BlendableLayer.FX, lc.playable);
Assert.IsTrue(actualLayers.Add(lc.layer));
}
}
Assert.That(expectedLayers, Is.EquivalentTo(actualLayers));
}
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 298d11b5361148b499d196aabcaaab73
timeCreated: 1742002556

View File

@ -0,0 +1,380 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &784701382543359949
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 8612238306248833727}
- component: {fileID: 3495771561595279164}
- component: {fileID: 1229959924919852631}
- component: {fileID: 6320176121826827791}
m_Layer: 0
m_Name: MMDMode_MergeBefore
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &8612238306248833727
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 784701382543359949}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: -0.02920363, y: 0.5853253, z: -0.39815798}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 7556123215267729845}
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!95 &3495771561595279164
Animator:
serializedVersion: 5
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 784701382543359949}
m_Enabled: 1
m_Avatar: {fileID: 0}
m_Controller: {fileID: 0}
m_CullingMode: 0
m_UpdateMode: 0
m_ApplyRootMotion: 0
m_LinearVelocityBlending: 0
m_StabilizeFeet: 0
m_WarningMessage:
m_HasTransformHierarchy: 1
m_AllowConstantClipSamplingOptimization: 1
m_KeepAnimatorStateOnDisable: 0
m_WriteDefaultValuesOnDisable: 0
--- !u!114 &1229959924919852631
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 784701382543359949}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 542108242, guid: 67cc4cb7839cd3741b63733d5adf0442, type: 3}
m_Name:
m_EditorClassIdentifier:
Name:
ViewPosition: {x: 0, y: 1.6, z: 0.2}
Animations: 0
ScaleIPD: 1
lipSync: 0
lipSyncJawBone: {fileID: 0}
lipSyncJawClosed: {x: 0, y: 0, z: 0, w: 1}
lipSyncJawOpen: {x: 0, y: 0, z: 0, w: 1}
VisemeSkinnedMesh: {fileID: 0}
MouthOpenBlendShapeName: Facial_Blends.Jaw_Down
VisemeBlendShapes: []
unityVersion:
portraitCameraPositionOffset: {x: 0, y: 0, z: 0}
portraitCameraRotationOffset: {x: 0, y: 1, z: 0, w: -0.00000004371139}
networkIDs: []
customExpressions: 1
expressionsMenu: {fileID: 0}
expressionParameters: {fileID: 0}
enableEyeLook: 0
customEyeLookSettings:
eyeMovement:
confidence: 0.5
excitement: 0.5
leftEye: {fileID: 0}
rightEye: {fileID: 0}
eyesLookingStraight:
linked: 1
left: {x: 0, y: 0, z: 0, w: 0}
right: {x: 0, y: 0, z: 0, w: 0}
eyesLookingUp:
linked: 1
left: {x: 0, y: 0, z: 0, w: 0}
right: {x: 0, y: 0, z: 0, w: 0}
eyesLookingDown:
linked: 1
left: {x: 0, y: 0, z: 0, w: 0}
right: {x: 0, y: 0, z: 0, w: 0}
eyesLookingLeft:
linked: 1
left: {x: 0, y: 0, z: 0, w: 0}
right: {x: 0, y: 0, z: 0, w: 0}
eyesLookingRight:
linked: 1
left: {x: 0, y: 0, z: 0, w: 0}
right: {x: 0, y: 0, z: 0, w: 0}
eyelidType: 0
upperLeftEyelid: {fileID: 0}
upperRightEyelid: {fileID: 0}
lowerLeftEyelid: {fileID: 0}
lowerRightEyelid: {fileID: 0}
eyelidsDefault:
upper:
linked: 1
left: {x: 0, y: 0, z: 0, w: 0}
right: {x: 0, y: 0, z: 0, w: 0}
lower:
linked: 1
left: {x: 0, y: 0, z: 0, w: 0}
right: {x: 0, y: 0, z: 0, w: 0}
eyelidsClosed:
upper:
linked: 1
left: {x: 0, y: 0, z: 0, w: 0}
right: {x: 0, y: 0, z: 0, w: 0}
lower:
linked: 1
left: {x: 0, y: 0, z: 0, w: 0}
right: {x: 0, y: 0, z: 0, w: 0}
eyelidsLookingUp:
upper:
linked: 1
left: {x: 0, y: 0, z: 0, w: 0}
right: {x: 0, y: 0, z: 0, w: 0}
lower:
linked: 1
left: {x: 0, y: 0, z: 0, w: 0}
right: {x: 0, y: 0, z: 0, w: 0}
eyelidsLookingDown:
upper:
linked: 1
left: {x: 0, y: 0, z: 0, w: 0}
right: {x: 0, y: 0, z: 0, w: 0}
lower:
linked: 1
left: {x: 0, y: 0, z: 0, w: 0}
right: {x: 0, y: 0, z: 0, w: 0}
eyelidsSkinnedMesh: {fileID: 0}
eyelidsBlendshapes:
customizeAnimationLayers: 1
baseAnimationLayers:
- isEnabled: 0
type: 0
animatorController: {fileID: 0}
mask: {fileID: 0}
isDefault: 1
- isEnabled: 0
type: 4
animatorController: {fileID: 0}
mask: {fileID: 0}
isDefault: 1
- isEnabled: 0
type: 5
animatorController: {fileID: 9100000, guid: e7f6321e9d2601a45a3efa0a24305b78,
type: 2}
mask: {fileID: 0}
isDefault: 0
specialAnimationLayers:
- isEnabled: 0
type: 6
animatorController: {fileID: 0}
mask: {fileID: 0}
isDefault: 1
- isEnabled: 0
type: 7
animatorController: {fileID: 0}
mask: {fileID: 0}
isDefault: 1
- isEnabled: 0
type: 8
animatorController: {fileID: 0}
mask: {fileID: 0}
isDefault: 1
AnimationPreset: {fileID: 0}
animationHashSet: []
autoFootsteps: 1
autoLocomotion: 1
collider_head:
isMirrored: 1
state: 0
transform: {fileID: 0}
radius: 0
height: 0
position: {x: 0, y: 0, z: 0}
rotation: {x: 0, y: 0, z: 0, w: 1}
collider_torso:
isMirrored: 1
state: 0
transform: {fileID: 0}
radius: 0
height: 0
position: {x: 0, y: 0, z: 0}
rotation: {x: 0, y: 0, z: 0, w: 1}
collider_footR:
isMirrored: 1
state: 0
transform: {fileID: 0}
radius: 0
height: 0
position: {x: 0, y: 0, z: 0}
rotation: {x: 0, y: 0, z: 0, w: 1}
collider_footL:
isMirrored: 1
state: 0
transform: {fileID: 0}
radius: 0
height: 0
position: {x: 0, y: 0, z: 0}
rotation: {x: 0, y: 0, z: 0, w: 1}
collider_handR:
isMirrored: 1
state: 0
transform: {fileID: 0}
radius: 0
height: 0
position: {x: 0, y: 0, z: 0}
rotation: {x: 0, y: 0, z: 0, w: 1}
collider_handL:
isMirrored: 1
state: 0
transform: {fileID: 0}
radius: 0
height: 0
position: {x: 0, y: 0, z: 0}
rotation: {x: 0, y: 0, z: 0, w: 1}
collider_fingerIndexL:
isMirrored: 1
state: 0
transform: {fileID: 0}
radius: 0
height: 0
position: {x: 0, y: 0, z: 0}
rotation: {x: 0, y: 0, z: 0, w: 1}
collider_fingerMiddleL:
isMirrored: 1
state: 0
transform: {fileID: 0}
radius: 0
height: 0
position: {x: 0, y: 0, z: 0}
rotation: {x: 0, y: 0, z: 0, w: 1}
collider_fingerRingL:
isMirrored: 1
state: 0
transform: {fileID: 0}
radius: 0
height: 0
position: {x: 0, y: 0, z: 0}
rotation: {x: 0, y: 0, z: 0, w: 1}
collider_fingerLittleL:
isMirrored: 1
state: 0
transform: {fileID: 0}
radius: 0
height: 0
position: {x: 0, y: 0, z: 0}
rotation: {x: 0, y: 0, z: 0, w: 1}
collider_fingerIndexR:
isMirrored: 1
state: 0
transform: {fileID: 0}
radius: 0
height: 0
position: {x: 0, y: 0, z: 0}
rotation: {x: 0, y: 0, z: 0, w: 1}
collider_fingerMiddleR:
isMirrored: 1
state: 0
transform: {fileID: 0}
radius: 0
height: 0
position: {x: 0, y: 0, z: 0}
rotation: {x: 0, y: 0, z: 0, w: 1}
collider_fingerRingR:
isMirrored: 1
state: 0
transform: {fileID: 0}
radius: 0
height: 0
position: {x: 0, y: 0, z: 0}
rotation: {x: 0, y: 0, z: 0, w: 1}
collider_fingerLittleR:
isMirrored: 1
state: 0
transform: {fileID: 0}
radius: 0
height: 0
position: {x: 0, y: 0, z: 0}
rotation: {x: 0, y: 0, z: 0, w: 1}
--- !u!114 &6320176121826827791
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 784701382543359949}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: -1427037861, guid: 4ecd63eff847044b68db9453ce219299, type: 3}
m_Name:
m_EditorClassIdentifier:
launchedFromSDKPipeline: 0
completedSDKPipeline: 0
blueprintId:
contentType: 0
assetBundleUnityVersion:
fallbackStatus: 0
--- !u!1 &8032631290352466631
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 7556123215267729845}
- component: {fileID: 2259268676535659146}
m_Layer: 0
m_Name: mergeBefore
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &7556123215267729845
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 8032631290352466631}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 8612238306248833727}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &2259268676535659146
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 8032631290352466631}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 1bb122659f724ebf85fe095ac02dc339, type: 3}
m_Name:
m_EditorClassIdentifier:
animator: {fileID: 9100000, guid: bf8dbf58ea7a7544cb5c7f86b790d0ff, type: 2}
layerType: 5
deleteAttachedAnimator: 1
pathMode: 0
matchAvatarWriteDefaults: 0
relativePathRoot:
referencePath:
targetObject: {fileID: 0}
layerPriority: -1
mergeAnimatorMode: 0

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 5cd01837b01aa8b4897906d81b421b32
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,325 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &252931896825782499
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 5142404049502950569}
- component: {fileID: 5869130456277801080}
- component: {fileID: 9098796828299356927}
- component: {fileID: 5312873765374103901}
m_Layer: 0
m_Name: MMDMode_Noop
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &5142404049502950569
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 252931896825782499}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: -0.02920363, y: 0.5853253, z: -0.39815798}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!95 &5869130456277801080
Animator:
serializedVersion: 5
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 252931896825782499}
m_Enabled: 1
m_Avatar: {fileID: 0}
m_Controller: {fileID: 0}
m_CullingMode: 0
m_UpdateMode: 0
m_ApplyRootMotion: 0
m_LinearVelocityBlending: 0
m_StabilizeFeet: 0
m_WarningMessage:
m_HasTransformHierarchy: 1
m_AllowConstantClipSamplingOptimization: 1
m_KeepAnimatorStateOnDisable: 0
m_WriteDefaultValuesOnDisable: 0
--- !u!114 &9098796828299356927
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 252931896825782499}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 542108242, guid: 67cc4cb7839cd3741b63733d5adf0442, type: 3}
m_Name:
m_EditorClassIdentifier:
Name:
ViewPosition: {x: 0, y: 1.6, z: 0.2}
Animations: 0
ScaleIPD: 1
lipSync: 0
lipSyncJawBone: {fileID: 0}
lipSyncJawClosed: {x: 0, y: 0, z: 0, w: 1}
lipSyncJawOpen: {x: 0, y: 0, z: 0, w: 1}
VisemeSkinnedMesh: {fileID: 0}
MouthOpenBlendShapeName: Facial_Blends.Jaw_Down
VisemeBlendShapes: []
unityVersion:
portraitCameraPositionOffset: {x: 0, y: 0, z: 0}
portraitCameraRotationOffset: {x: 0, y: 1, z: 0, w: -0.00000004371139}
networkIDs: []
customExpressions: 1
expressionsMenu: {fileID: 0}
expressionParameters: {fileID: 0}
enableEyeLook: 0
customEyeLookSettings:
eyeMovement:
confidence: 0.5
excitement: 0.5
leftEye: {fileID: 0}
rightEye: {fileID: 0}
eyesLookingStraight:
linked: 1
left: {x: 0, y: 0, z: 0, w: 0}
right: {x: 0, y: 0, z: 0, w: 0}
eyesLookingUp:
linked: 1
left: {x: 0, y: 0, z: 0, w: 0}
right: {x: 0, y: 0, z: 0, w: 0}
eyesLookingDown:
linked: 1
left: {x: 0, y: 0, z: 0, w: 0}
right: {x: 0, y: 0, z: 0, w: 0}
eyesLookingLeft:
linked: 1
left: {x: 0, y: 0, z: 0, w: 0}
right: {x: 0, y: 0, z: 0, w: 0}
eyesLookingRight:
linked: 1
left: {x: 0, y: 0, z: 0, w: 0}
right: {x: 0, y: 0, z: 0, w: 0}
eyelidType: 0
upperLeftEyelid: {fileID: 0}
upperRightEyelid: {fileID: 0}
lowerLeftEyelid: {fileID: 0}
lowerRightEyelid: {fileID: 0}
eyelidsDefault:
upper:
linked: 1
left: {x: 0, y: 0, z: 0, w: 0}
right: {x: 0, y: 0, z: 0, w: 0}
lower:
linked: 1
left: {x: 0, y: 0, z: 0, w: 0}
right: {x: 0, y: 0, z: 0, w: 0}
eyelidsClosed:
upper:
linked: 1
left: {x: 0, y: 0, z: 0, w: 0}
right: {x: 0, y: 0, z: 0, w: 0}
lower:
linked: 1
left: {x: 0, y: 0, z: 0, w: 0}
right: {x: 0, y: 0, z: 0, w: 0}
eyelidsLookingUp:
upper:
linked: 1
left: {x: 0, y: 0, z: 0, w: 0}
right: {x: 0, y: 0, z: 0, w: 0}
lower:
linked: 1
left: {x: 0, y: 0, z: 0, w: 0}
right: {x: 0, y: 0, z: 0, w: 0}
eyelidsLookingDown:
upper:
linked: 1
left: {x: 0, y: 0, z: 0, w: 0}
right: {x: 0, y: 0, z: 0, w: 0}
lower:
linked: 1
left: {x: 0, y: 0, z: 0, w: 0}
right: {x: 0, y: 0, z: 0, w: 0}
eyelidsSkinnedMesh: {fileID: 0}
eyelidsBlendshapes:
customizeAnimationLayers: 1
baseAnimationLayers:
- isEnabled: 0
type: 0
animatorController: {fileID: 0}
mask: {fileID: 0}
isDefault: 1
- isEnabled: 0
type: 4
animatorController: {fileID: 0}
mask: {fileID: 0}
isDefault: 1
- isEnabled: 0
type: 5
animatorController: {fileID: 9100000, guid: e7f6321e9d2601a45a3efa0a24305b78,
type: 2}
mask: {fileID: 0}
isDefault: 0
specialAnimationLayers:
- isEnabled: 0
type: 6
animatorController: {fileID: 0}
mask: {fileID: 0}
isDefault: 1
- isEnabled: 0
type: 7
animatorController: {fileID: 0}
mask: {fileID: 0}
isDefault: 1
- isEnabled: 0
type: 8
animatorController: {fileID: 0}
mask: {fileID: 0}
isDefault: 1
AnimationPreset: {fileID: 0}
animationHashSet: []
autoFootsteps: 1
autoLocomotion: 1
collider_head:
isMirrored: 1
state: 0
transform: {fileID: 0}
radius: 0
height: 0
position: {x: 0, y: 0, z: 0}
rotation: {x: 0, y: 0, z: 0, w: 1}
collider_torso:
isMirrored: 1
state: 0
transform: {fileID: 0}
radius: 0
height: 0
position: {x: 0, y: 0, z: 0}
rotation: {x: 0, y: 0, z: 0, w: 1}
collider_footR:
isMirrored: 1
state: 0
transform: {fileID: 0}
radius: 0
height: 0
position: {x: 0, y: 0, z: 0}
rotation: {x: 0, y: 0, z: 0, w: 1}
collider_footL:
isMirrored: 1
state: 0
transform: {fileID: 0}
radius: 0
height: 0
position: {x: 0, y: 0, z: 0}
rotation: {x: 0, y: 0, z: 0, w: 1}
collider_handR:
isMirrored: 1
state: 0
transform: {fileID: 0}
radius: 0
height: 0
position: {x: 0, y: 0, z: 0}
rotation: {x: 0, y: 0, z: 0, w: 1}
collider_handL:
isMirrored: 1
state: 0
transform: {fileID: 0}
radius: 0
height: 0
position: {x: 0, y: 0, z: 0}
rotation: {x: 0, y: 0, z: 0, w: 1}
collider_fingerIndexL:
isMirrored: 1
state: 0
transform: {fileID: 0}
radius: 0
height: 0
position: {x: 0, y: 0, z: 0}
rotation: {x: 0, y: 0, z: 0, w: 1}
collider_fingerMiddleL:
isMirrored: 1
state: 0
transform: {fileID: 0}
radius: 0
height: 0
position: {x: 0, y: 0, z: 0}
rotation: {x: 0, y: 0, z: 0, w: 1}
collider_fingerRingL:
isMirrored: 1
state: 0
transform: {fileID: 0}
radius: 0
height: 0
position: {x: 0, y: 0, z: 0}
rotation: {x: 0, y: 0, z: 0, w: 1}
collider_fingerLittleL:
isMirrored: 1
state: 0
transform: {fileID: 0}
radius: 0
height: 0
position: {x: 0, y: 0, z: 0}
rotation: {x: 0, y: 0, z: 0, w: 1}
collider_fingerIndexR:
isMirrored: 1
state: 0
transform: {fileID: 0}
radius: 0
height: 0
position: {x: 0, y: 0, z: 0}
rotation: {x: 0, y: 0, z: 0, w: 1}
collider_fingerMiddleR:
isMirrored: 1
state: 0
transform: {fileID: 0}
radius: 0
height: 0
position: {x: 0, y: 0, z: 0}
rotation: {x: 0, y: 0, z: 0, w: 1}
collider_fingerRingR:
isMirrored: 1
state: 0
transform: {fileID: 0}
radius: 0
height: 0
position: {x: 0, y: 0, z: 0}
rotation: {x: 0, y: 0, z: 0, w: 1}
collider_fingerLittleR:
isMirrored: 1
state: 0
transform: {fileID: 0}
radius: 0
height: 0
position: {x: 0, y: 0, z: 0}
rotation: {x: 0, y: 0, z: 0, w: 1}
--- !u!114 &5312873765374103901
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 252931896825782499}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: -1427037861, guid: 4ecd63eff847044b68db9453ce219299, type: 3}
m_Name:
m_EditorClassIdentifier:
launchedFromSDKPipeline: 0
completedSDKPipeline: 0
blueprintId:
contentType: 0
assetBundleUnityVersion:
fallbackStatus: 0

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 9467ce2e34cfbc74aa9cb6ed1b990488
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,325 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &3649483952032229877
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 3671950317217900310}
- component: {fileID: 5516575333733947756}
- component: {fileID: 3355915580969342691}
- component: {fileID: 8742850335181783537}
m_Layer: 0
m_Name: MMDMode_Overrides
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &3671950317217900310
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 3649483952032229877}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: -0.02920363, y: 0.5853253, z: -0.39815798}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!95 &5516575333733947756
Animator:
serializedVersion: 5
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 3649483952032229877}
m_Enabled: 1
m_Avatar: {fileID: 0}
m_Controller: {fileID: 0}
m_CullingMode: 0
m_UpdateMode: 0
m_ApplyRootMotion: 0
m_LinearVelocityBlending: 0
m_StabilizeFeet: 0
m_WarningMessage:
m_HasTransformHierarchy: 1
m_AllowConstantClipSamplingOptimization: 1
m_KeepAnimatorStateOnDisable: 0
m_WriteDefaultValuesOnDisable: 0
--- !u!114 &3355915580969342691
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 3649483952032229877}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 542108242, guid: 67cc4cb7839cd3741b63733d5adf0442, type: 3}
m_Name:
m_EditorClassIdentifier:
Name:
ViewPosition: {x: 0, y: 1.6, z: 0.2}
Animations: 0
ScaleIPD: 1
lipSync: 0
lipSyncJawBone: {fileID: 0}
lipSyncJawClosed: {x: 0, y: 0, z: 0, w: 1}
lipSyncJawOpen: {x: 0, y: 0, z: 0, w: 1}
VisemeSkinnedMesh: {fileID: 0}
MouthOpenBlendShapeName: Facial_Blends.Jaw_Down
VisemeBlendShapes: []
unityVersion:
portraitCameraPositionOffset: {x: 0, y: 0, z: 0}
portraitCameraRotationOffset: {x: 0, y: 1, z: 0, w: -0.00000004371139}
networkIDs: []
customExpressions: 1
expressionsMenu: {fileID: 0}
expressionParameters: {fileID: 0}
enableEyeLook: 0
customEyeLookSettings:
eyeMovement:
confidence: 0.5
excitement: 0.5
leftEye: {fileID: 0}
rightEye: {fileID: 0}
eyesLookingStraight:
linked: 1
left: {x: 0, y: 0, z: 0, w: 0}
right: {x: 0, y: 0, z: 0, w: 0}
eyesLookingUp:
linked: 1
left: {x: 0, y: 0, z: 0, w: 0}
right: {x: 0, y: 0, z: 0, w: 0}
eyesLookingDown:
linked: 1
left: {x: 0, y: 0, z: 0, w: 0}
right: {x: 0, y: 0, z: 0, w: 0}
eyesLookingLeft:
linked: 1
left: {x: 0, y: 0, z: 0, w: 0}
right: {x: 0, y: 0, z: 0, w: 0}
eyesLookingRight:
linked: 1
left: {x: 0, y: 0, z: 0, w: 0}
right: {x: 0, y: 0, z: 0, w: 0}
eyelidType: 0
upperLeftEyelid: {fileID: 0}
upperRightEyelid: {fileID: 0}
lowerLeftEyelid: {fileID: 0}
lowerRightEyelid: {fileID: 0}
eyelidsDefault:
upper:
linked: 1
left: {x: 0, y: 0, z: 0, w: 0}
right: {x: 0, y: 0, z: 0, w: 0}
lower:
linked: 1
left: {x: 0, y: 0, z: 0, w: 0}
right: {x: 0, y: 0, z: 0, w: 0}
eyelidsClosed:
upper:
linked: 1
left: {x: 0, y: 0, z: 0, w: 0}
right: {x: 0, y: 0, z: 0, w: 0}
lower:
linked: 1
left: {x: 0, y: 0, z: 0, w: 0}
right: {x: 0, y: 0, z: 0, w: 0}
eyelidsLookingUp:
upper:
linked: 1
left: {x: 0, y: 0, z: 0, w: 0}
right: {x: 0, y: 0, z: 0, w: 0}
lower:
linked: 1
left: {x: 0, y: 0, z: 0, w: 0}
right: {x: 0, y: 0, z: 0, w: 0}
eyelidsLookingDown:
upper:
linked: 1
left: {x: 0, y: 0, z: 0, w: 0}
right: {x: 0, y: 0, z: 0, w: 0}
lower:
linked: 1
left: {x: 0, y: 0, z: 0, w: 0}
right: {x: 0, y: 0, z: 0, w: 0}
eyelidsSkinnedMesh: {fileID: 0}
eyelidsBlendshapes:
customizeAnimationLayers: 1
baseAnimationLayers:
- isEnabled: 0
type: 0
animatorController: {fileID: 0}
mask: {fileID: 0}
isDefault: 1
- isEnabled: 0
type: 4
animatorController: {fileID: 0}
mask: {fileID: 0}
isDefault: 1
- isEnabled: 0
type: 5
animatorController: {fileID: 9100000, guid: 9aedd84d3acd0db4384c04f9b136ecb1,
type: 2}
mask: {fileID: 0}
isDefault: 0
specialAnimationLayers:
- isEnabled: 0
type: 6
animatorController: {fileID: 0}
mask: {fileID: 0}
isDefault: 1
- isEnabled: 0
type: 7
animatorController: {fileID: 0}
mask: {fileID: 0}
isDefault: 1
- isEnabled: 0
type: 8
animatorController: {fileID: 0}
mask: {fileID: 0}
isDefault: 1
AnimationPreset: {fileID: 0}
animationHashSet: []
autoFootsteps: 1
autoLocomotion: 1
collider_head:
isMirrored: 1
state: 0
transform: {fileID: 0}
radius: 0
height: 0
position: {x: 0, y: 0, z: 0}
rotation: {x: 0, y: 0, z: 0, w: 1}
collider_torso:
isMirrored: 1
state: 0
transform: {fileID: 0}
radius: 0
height: 0
position: {x: 0, y: 0, z: 0}
rotation: {x: 0, y: 0, z: 0, w: 1}
collider_footR:
isMirrored: 1
state: 0
transform: {fileID: 0}
radius: 0
height: 0
position: {x: 0, y: 0, z: 0}
rotation: {x: 0, y: 0, z: 0, w: 1}
collider_footL:
isMirrored: 1
state: 0
transform: {fileID: 0}
radius: 0
height: 0
position: {x: 0, y: 0, z: 0}
rotation: {x: 0, y: 0, z: 0, w: 1}
collider_handR:
isMirrored: 1
state: 0
transform: {fileID: 0}
radius: 0
height: 0
position: {x: 0, y: 0, z: 0}
rotation: {x: 0, y: 0, z: 0, w: 1}
collider_handL:
isMirrored: 1
state: 0
transform: {fileID: 0}
radius: 0
height: 0
position: {x: 0, y: 0, z: 0}
rotation: {x: 0, y: 0, z: 0, w: 1}
collider_fingerIndexL:
isMirrored: 1
state: 0
transform: {fileID: 0}
radius: 0
height: 0
position: {x: 0, y: 0, z: 0}
rotation: {x: 0, y: 0, z: 0, w: 1}
collider_fingerMiddleL:
isMirrored: 1
state: 0
transform: {fileID: 0}
radius: 0
height: 0
position: {x: 0, y: 0, z: 0}
rotation: {x: 0, y: 0, z: 0, w: 1}
collider_fingerRingL:
isMirrored: 1
state: 0
transform: {fileID: 0}
radius: 0
height: 0
position: {x: 0, y: 0, z: 0}
rotation: {x: 0, y: 0, z: 0, w: 1}
collider_fingerLittleL:
isMirrored: 1
state: 0
transform: {fileID: 0}
radius: 0
height: 0
position: {x: 0, y: 0, z: 0}
rotation: {x: 0, y: 0, z: 0, w: 1}
collider_fingerIndexR:
isMirrored: 1
state: 0
transform: {fileID: 0}
radius: 0
height: 0
position: {x: 0, y: 0, z: 0}
rotation: {x: 0, y: 0, z: 0, w: 1}
collider_fingerMiddleR:
isMirrored: 1
state: 0
transform: {fileID: 0}
radius: 0
height: 0
position: {x: 0, y: 0, z: 0}
rotation: {x: 0, y: 0, z: 0, w: 1}
collider_fingerRingR:
isMirrored: 1
state: 0
transform: {fileID: 0}
radius: 0
height: 0
position: {x: 0, y: 0, z: 0}
rotation: {x: 0, y: 0, z: 0, w: 1}
collider_fingerLittleR:
isMirrored: 1
state: 0
transform: {fileID: 0}
radius: 0
height: 0
position: {x: 0, y: 0, z: 0}
rotation: {x: 0, y: 0, z: 0, w: 1}
--- !u!114 &8742850335181783537
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 3649483952032229877}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: -1427037861, guid: 4ecd63eff847044b68db9453ce219299, type: 3}
m_Name:
m_EditorClassIdentifier:
launchedFromSDKPipeline: 0
completedSDKPipeline: 0
blueprintId:
contentType: 0
assetBundleUnityVersion:
fallbackStatus: 0

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 1880667773f814c49922924e24005b29
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,454 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &1386134902351561831
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 6342890467153306326}
- component: {fileID: 6952234223613419749}
- component: {fileID: 8569547807942057610}
- component: {fileID: 5205561095749141078}
m_Layer: 0
m_Name: GameObject Toggle
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &6342890467153306326
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1386134902351561831}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 4605622065467040953}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &6952234223613419749
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1386134902351561831}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: a162bb8ec7e24a5abcf457887f1df3fa, type: 3}
m_Name:
m_EditorClassIdentifier:
m_inverted: 0
m_objects:
- Object:
referencePath: GameObject
targetObject: {fileID: 4583133230356327828}
Active: 0
--- !u!114 &8569547807942057610
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1386134902351561831}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 3b29d45007c5493d926d2cd45a489529, type: 3}
m_Name:
m_EditorClassIdentifier:
Control:
name: GameObject Toggle
icon: {fileID: 0}
type: 102
parameter:
name:
value: 1
style: 0
subMenu: {fileID: 0}
subParameters: []
labels: []
MenuSource: 1
menuSource_otherObjectChildren: {fileID: 0}
isSynced: 1
isSaved: 1
isDefault: 0
automaticValue: 1
label:
--- !u!114 &5205561095749141078
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1386134902351561831}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 7ef83cb0c23d4d7c9d41021e544a1978, type: 3}
m_Name:
m_EditorClassIdentifier:
menuToAppend: {fileID: 0}
installTargetMenu: {fileID: 0}
--- !u!1 &4583133230356327828
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 3143043948112966587}
m_Layer: 0
m_Name: GameObject
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &3143043948112966587
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4583133230356327828}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 4605622065467040953}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &6783015114988609388
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 4605622065467040953}
- component: {fileID: 2545551016003718416}
- component: {fileID: 7974059650307163264}
- component: {fileID: 6183713000671264849}
m_Layer: 0
m_Name: MMDMode_Reactive
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &4605622065467040953
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6783015114988609388}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: -0.02920363, y: 0.5853253, z: -0.39815798}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 3143043948112966587}
- {fileID: 6342890467153306326}
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!95 &2545551016003718416
Animator:
serializedVersion: 5
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6783015114988609388}
m_Enabled: 1
m_Avatar: {fileID: 0}
m_Controller: {fileID: 0}
m_CullingMode: 0
m_UpdateMode: 0
m_ApplyRootMotion: 0
m_LinearVelocityBlending: 0
m_StabilizeFeet: 0
m_WarningMessage:
m_HasTransformHierarchy: 1
m_AllowConstantClipSamplingOptimization: 1
m_KeepAnimatorStateOnDisable: 0
m_WriteDefaultValuesOnDisable: 0
--- !u!114 &7974059650307163264
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6783015114988609388}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 542108242, guid: 67cc4cb7839cd3741b63733d5adf0442, type: 3}
m_Name:
m_EditorClassIdentifier:
Name:
ViewPosition: {x: 0, y: 1.6, z: 0.2}
Animations: 0
ScaleIPD: 1
lipSync: 0
lipSyncJawBone: {fileID: 0}
lipSyncJawClosed: {x: 0, y: 0, z: 0, w: 1}
lipSyncJawOpen: {x: 0, y: 0, z: 0, w: 1}
VisemeSkinnedMesh: {fileID: 0}
MouthOpenBlendShapeName: Facial_Blends.Jaw_Down
VisemeBlendShapes: []
unityVersion:
portraitCameraPositionOffset: {x: 0, y: 0, z: 0}
portraitCameraRotationOffset: {x: 0, y: 1, z: 0, w: -0.00000004371139}
networkIDs: []
customExpressions: 1
expressionsMenu: {fileID: 0}
expressionParameters: {fileID: 0}
enableEyeLook: 0
customEyeLookSettings:
eyeMovement:
confidence: 0.5
excitement: 0.5
leftEye: {fileID: 0}
rightEye: {fileID: 0}
eyesLookingStraight:
linked: 1
left: {x: 0, y: 0, z: 0, w: 0}
right: {x: 0, y: 0, z: 0, w: 0}
eyesLookingUp:
linked: 1
left: {x: 0, y: 0, z: 0, w: 0}
right: {x: 0, y: 0, z: 0, w: 0}
eyesLookingDown:
linked: 1
left: {x: 0, y: 0, z: 0, w: 0}
right: {x: 0, y: 0, z: 0, w: 0}
eyesLookingLeft:
linked: 1
left: {x: 0, y: 0, z: 0, w: 0}
right: {x: 0, y: 0, z: 0, w: 0}
eyesLookingRight:
linked: 1
left: {x: 0, y: 0, z: 0, w: 0}
right: {x: 0, y: 0, z: 0, w: 0}
eyelidType: 0
upperLeftEyelid: {fileID: 0}
upperRightEyelid: {fileID: 0}
lowerLeftEyelid: {fileID: 0}
lowerRightEyelid: {fileID: 0}
eyelidsDefault:
upper:
linked: 1
left: {x: 0, y: 0, z: 0, w: 0}
right: {x: 0, y: 0, z: 0, w: 0}
lower:
linked: 1
left: {x: 0, y: 0, z: 0, w: 0}
right: {x: 0, y: 0, z: 0, w: 0}
eyelidsClosed:
upper:
linked: 1
left: {x: 0, y: 0, z: 0, w: 0}
right: {x: 0, y: 0, z: 0, w: 0}
lower:
linked: 1
left: {x: 0, y: 0, z: 0, w: 0}
right: {x: 0, y: 0, z: 0, w: 0}
eyelidsLookingUp:
upper:
linked: 1
left: {x: 0, y: 0, z: 0, w: 0}
right: {x: 0, y: 0, z: 0, w: 0}
lower:
linked: 1
left: {x: 0, y: 0, z: 0, w: 0}
right: {x: 0, y: 0, z: 0, w: 0}
eyelidsLookingDown:
upper:
linked: 1
left: {x: 0, y: 0, z: 0, w: 0}
right: {x: 0, y: 0, z: 0, w: 0}
lower:
linked: 1
left: {x: 0, y: 0, z: 0, w: 0}
right: {x: 0, y: 0, z: 0, w: 0}
eyelidsSkinnedMesh: {fileID: 0}
eyelidsBlendshapes:
customizeAnimationLayers: 1
baseAnimationLayers:
- isEnabled: 0
type: 0
animatorController: {fileID: 0}
mask: {fileID: 0}
isDefault: 1
- isEnabled: 0
type: 4
animatorController: {fileID: 0}
mask: {fileID: 0}
isDefault: 1
- isEnabled: 0
type: 5
animatorController: {fileID: 9100000, guid: e7f6321e9d2601a45a3efa0a24305b78,
type: 2}
mask: {fileID: 0}
isDefault: 0
specialAnimationLayers:
- isEnabled: 0
type: 6
animatorController: {fileID: 0}
mask: {fileID: 0}
isDefault: 1
- isEnabled: 0
type: 7
animatorController: {fileID: 0}
mask: {fileID: 0}
isDefault: 1
- isEnabled: 0
type: 8
animatorController: {fileID: 0}
mask: {fileID: 0}
isDefault: 1
AnimationPreset: {fileID: 0}
animationHashSet: []
autoFootsteps: 1
autoLocomotion: 1
collider_head:
isMirrored: 1
state: 0
transform: {fileID: 0}
radius: 0
height: 0
position: {x: 0, y: 0, z: 0}
rotation: {x: 0, y: 0, z: 0, w: 1}
collider_torso:
isMirrored: 1
state: 0
transform: {fileID: 0}
radius: 0
height: 0
position: {x: 0, y: 0, z: 0}
rotation: {x: 0, y: 0, z: 0, w: 1}
collider_footR:
isMirrored: 1
state: 0
transform: {fileID: 0}
radius: 0
height: 0
position: {x: 0, y: 0, z: 0}
rotation: {x: 0, y: 0, z: 0, w: 1}
collider_footL:
isMirrored: 1
state: 0
transform: {fileID: 0}
radius: 0
height: 0
position: {x: 0, y: 0, z: 0}
rotation: {x: 0, y: 0, z: 0, w: 1}
collider_handR:
isMirrored: 1
state: 0
transform: {fileID: 0}
radius: 0
height: 0
position: {x: 0, y: 0, z: 0}
rotation: {x: 0, y: 0, z: 0, w: 1}
collider_handL:
isMirrored: 1
state: 0
transform: {fileID: 0}
radius: 0
height: 0
position: {x: 0, y: 0, z: 0}
rotation: {x: 0, y: 0, z: 0, w: 1}
collider_fingerIndexL:
isMirrored: 1
state: 0
transform: {fileID: 0}
radius: 0
height: 0
position: {x: 0, y: 0, z: 0}
rotation: {x: 0, y: 0, z: 0, w: 1}
collider_fingerMiddleL:
isMirrored: 1
state: 0
transform: {fileID: 0}
radius: 0
height: 0
position: {x: 0, y: 0, z: 0}
rotation: {x: 0, y: 0, z: 0, w: 1}
collider_fingerRingL:
isMirrored: 1
state: 0
transform: {fileID: 0}
radius: 0
height: 0
position: {x: 0, y: 0, z: 0}
rotation: {x: 0, y: 0, z: 0, w: 1}
collider_fingerLittleL:
isMirrored: 1
state: 0
transform: {fileID: 0}
radius: 0
height: 0
position: {x: 0, y: 0, z: 0}
rotation: {x: 0, y: 0, z: 0, w: 1}
collider_fingerIndexR:
isMirrored: 1
state: 0
transform: {fileID: 0}
radius: 0
height: 0
position: {x: 0, y: 0, z: 0}
rotation: {x: 0, y: 0, z: 0, w: 1}
collider_fingerMiddleR:
isMirrored: 1
state: 0
transform: {fileID: 0}
radius: 0
height: 0
position: {x: 0, y: 0, z: 0}
rotation: {x: 0, y: 0, z: 0, w: 1}
collider_fingerRingR:
isMirrored: 1
state: 0
transform: {fileID: 0}
radius: 0
height: 0
position: {x: 0, y: 0, z: 0}
rotation: {x: 0, y: 0, z: 0, w: 1}
collider_fingerLittleR:
isMirrored: 1
state: 0
transform: {fileID: 0}
radius: 0
height: 0
position: {x: 0, y: 0, z: 0}
rotation: {x: 0, y: 0, z: 0, w: 1}
--- !u!114 &6183713000671264849
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6783015114988609388}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: -1427037861, guid: 4ecd63eff847044b68db9453ce219299, type: 3}
m_Name:
m_EditorClassIdentifier:
launchedFromSDKPipeline: 0
completedSDKPipeline: 0
blueprintId:
contentType: 0
assetBundleUnityVersion:
fallbackStatus: 0

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 38d357295bfc91b499787e9c3e9e5fc1
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,340 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1102 &-7355338869790508137
AnimatorState:
serializedVersion: 6
m_ObjectHideFlags: 1
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: empty
m_Speed: 1
m_CycleOffset: 0
m_Transitions: []
m_StateMachineBehaviours: []
m_Position: {x: 50, y: 50, z: 0}
m_IKOnFeet: 0
m_WriteDefaultValues: 1
m_Mirror: 0
m_SpeedParameterActive: 0
m_MirrorParameterActive: 0
m_CycleOffsetParameterActive: 0
m_TimeParameterActive: 0
m_Motion: {fileID: 7400000, guid: 931318d79958463468b9ca3d48c96186, type: 2}
m_Tag:
m_SpeedParameter:
m_MirrorParameter:
m_CycleOffsetParameter:
m_TimeParameter:
--- !u!114 &-6326018740725076774
MonoBehaviour:
m_ObjectHideFlags: 1
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: d1d979d3cedd4ddd969f414e2ea04fb8, type: 3}
m_Name:
m_EditorClassIdentifier:
m_DisableInMMDMode: 1
--- !u!1102 &-4845154332522161829
AnimatorState:
serializedVersion: 6
m_ObjectHideFlags: 1
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: empty
m_Speed: 1
m_CycleOffset: 0
m_Transitions: []
m_StateMachineBehaviours: []
m_Position: {x: 50, y: 50, z: 0}
m_IKOnFeet: 0
m_WriteDefaultValues: 1
m_Mirror: 0
m_SpeedParameterActive: 0
m_MirrorParameterActive: 0
m_CycleOffsetParameterActive: 0
m_TimeParameterActive: 0
m_Motion: {fileID: 7400000, guid: 931318d79958463468b9ca3d48c96186, type: 2}
m_Tag:
m_SpeedParameter:
m_MirrorParameter:
m_CycleOffsetParameter:
m_TimeParameter:
--- !u!1107 &-3747905681079763705
AnimatorStateMachine:
serializedVersion: 6
m_ObjectHideFlags: 1
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: ForceOn
m_ChildStates:
- serializedVersion: 1
m_State: {fileID: -4845154332522161829}
m_Position: {x: 461.43958, y: -41.875793, z: 0}
m_ChildStateMachines: []
m_AnyStateTransitions: []
m_EntryTransitions: []
m_StateMachineTransitions: {}
m_StateMachineBehaviours:
- {fileID: -6326018740725076774}
m_AnyStatePosition: {x: 50, y: 20, z: 0}
m_EntryPosition: {x: 50, y: 120, z: 0}
m_ExitPosition: {x: 800, y: 120, z: 0}
m_ParentStateMachinePosition: {x: 800, y: 20, z: 0}
m_DefaultState: {fileID: -4845154332522161829}
--- !u!1107 &-3477861051435458144
AnimatorStateMachine:
serializedVersion: 6
m_ObjectHideFlags: 1
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: Base
m_ChildStates:
- serializedVersion: 1
m_State: {fileID: -7355338869790508137}
m_Position: {x: 441.0094, y: 127.91522, z: 0}
m_ChildStateMachines: []
m_AnyStateTransitions: []
m_EntryTransitions: []
m_StateMachineTransitions: {}
m_StateMachineBehaviours: []
m_AnyStatePosition: {x: 50, y: 20, z: 0}
m_EntryPosition: {x: 50, y: 120, z: 0}
m_ExitPosition: {x: 800, y: 120, z: 0}
m_ParentStateMachinePosition: {x: 800, y: 20, z: 0}
m_DefaultState: {fileID: -7355338869790508137}
--- !u!1107 &-3163258767259997666
AnimatorStateMachine:
serializedVersion: 6
m_ObjectHideFlags: 1
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: DefaultOn
m_ChildStates:
- serializedVersion: 1
m_State: {fileID: 2165750007709086016}
m_Position: {x: 320, y: 130, z: 0}
m_ChildStateMachines: []
m_AnyStateTransitions: []
m_EntryTransitions: []
m_StateMachineTransitions: {}
m_StateMachineBehaviours: []
m_AnyStatePosition: {x: 50, y: 20, z: 0}
m_EntryPosition: {x: 50, y: 120, z: 0}
m_ExitPosition: {x: 800, y: 120, z: 0}
m_ParentStateMachinePosition: {x: 800, y: 20, z: 0}
m_DefaultState: {fileID: 2165750007709086016}
--- !u!91 &9100000
AnimatorController:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: Overrides
serializedVersion: 5
m_AnimatorParameters: []
m_AnimatorLayers:
- serializedVersion: 5
m_Name: Base
m_StateMachine: {fileID: -3477861051435458144}
m_Mask: {fileID: 0}
m_Motions: []
m_Behaviours: []
m_BlendingMode: 0
m_SyncedLayerIndex: -1
m_DefaultWeight: 0
m_IKPass: 0
m_SyncedLayerAffectsTiming: 0
m_Controller: {fileID: 9100000}
- serializedVersion: 5
m_Name: ForceOff
m_StateMachine: {fileID: 3734055781436131242}
m_Mask: {fileID: 0}
m_Motions: []
m_Behaviours: []
m_BlendingMode: 0
m_SyncedLayerIndex: -1
m_DefaultWeight: 1
m_IKPass: 0
m_SyncedLayerAffectsTiming: 0
m_Controller: {fileID: 9100000}
- serializedVersion: 5
m_Name: DefaultOn
m_StateMachine: {fileID: -3163258767259997666}
m_Mask: {fileID: 0}
m_Motions: []
m_Behaviours: []
m_BlendingMode: 0
m_SyncedLayerIndex: -1
m_DefaultWeight: 1
m_IKPass: 0
m_SyncedLayerAffectsTiming: 0
m_Controller: {fileID: 9100000}
- serializedVersion: 5
m_Name: DefaultOff
m_StateMachine: {fileID: 6393666339861909369}
m_Mask: {fileID: 0}
m_Motions: []
m_Behaviours: []
m_BlendingMode: 0
m_SyncedLayerIndex: -1
m_DefaultWeight: 1
m_IKPass: 0
m_SyncedLayerAffectsTiming: 0
m_Controller: {fileID: 9100000}
- serializedVersion: 5
m_Name: ForceOn
m_StateMachine: {fileID: -3747905681079763705}
m_Mask: {fileID: 0}
m_Motions: []
m_Behaviours: []
m_BlendingMode: 0
m_SyncedLayerIndex: -1
m_DefaultWeight: 1
m_IKPass: 0
m_SyncedLayerAffectsTiming: 0
m_Controller: {fileID: 9100000}
--- !u!1102 &2165750007709086016
AnimatorState:
serializedVersion: 6
m_ObjectHideFlags: 1
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: empty
m_Speed: 1
m_CycleOffset: 0
m_Transitions: []
m_StateMachineBehaviours: []
m_Position: {x: 50, y: 50, z: 0}
m_IKOnFeet: 0
m_WriteDefaultValues: 1
m_Mirror: 0
m_SpeedParameterActive: 0
m_MirrorParameterActive: 0
m_CycleOffsetParameterActive: 0
m_TimeParameterActive: 0
m_Motion: {fileID: 7400000, guid: 931318d79958463468b9ca3d48c96186, type: 2}
m_Tag:
m_SpeedParameter:
m_MirrorParameter:
m_CycleOffsetParameter:
m_TimeParameter:
--- !u!114 &3283455143269254731
MonoBehaviour:
m_ObjectHideFlags: 1
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: d1d979d3cedd4ddd969f414e2ea04fb8, type: 3}
m_Name:
m_EditorClassIdentifier:
m_DisableInMMDMode: 0
--- !u!1102 &3470771388114793831
AnimatorState:
serializedVersion: 6
m_ObjectHideFlags: 1
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: empty
m_Speed: 1
m_CycleOffset: 0
m_Transitions: []
m_StateMachineBehaviours: []
m_Position: {x: 50, y: 50, z: 0}
m_IKOnFeet: 0
m_WriteDefaultValues: 1
m_Mirror: 0
m_SpeedParameterActive: 0
m_MirrorParameterActive: 0
m_CycleOffsetParameterActive: 0
m_TimeParameterActive: 0
m_Motion: {fileID: 7400000, guid: 931318d79958463468b9ca3d48c96186, type: 2}
m_Tag:
m_SpeedParameter:
m_MirrorParameter:
m_CycleOffsetParameter:
m_TimeParameter:
--- !u!1107 &3734055781436131242
AnimatorStateMachine:
serializedVersion: 6
m_ObjectHideFlags: 1
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: ForceOff
m_ChildStates:
- serializedVersion: 1
m_State: {fileID: 3470771388114793831}
m_Position: {x: 495.48987, y: 46.194702, z: 0}
m_ChildStateMachines: []
m_AnyStateTransitions: []
m_EntryTransitions: []
m_StateMachineTransitions: {}
m_StateMachineBehaviours:
- {fileID: 3283455143269254731}
m_AnyStatePosition: {x: 50, y: 20, z: 0}
m_EntryPosition: {x: 50, y: 120, z: 0}
m_ExitPosition: {x: 800, y: 120, z: 0}
m_ParentStateMachinePosition: {x: 800, y: 20, z: 0}
m_DefaultState: {fileID: 3470771388114793831}
--- !u!1107 &6393666339861909369
AnimatorStateMachine:
serializedVersion: 6
m_ObjectHideFlags: 1
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: DefaultOff
m_ChildStates:
- serializedVersion: 1
m_State: {fileID: 8588877275217762460}
m_Position: {x: 638.5006, y: 477.95697, z: 0}
m_ChildStateMachines: []
m_AnyStateTransitions: []
m_EntryTransitions: []
m_StateMachineTransitions: {}
m_StateMachineBehaviours: []
m_AnyStatePosition: {x: 50, y: 20, z: 0}
m_EntryPosition: {x: 50, y: 120, z: 0}
m_ExitPosition: {x: 800, y: 120, z: 0}
m_ParentStateMachinePosition: {x: 800, y: 20, z: 0}
m_DefaultState: {fileID: 8588877275217762460}
--- !u!1102 &8588877275217762460
AnimatorState:
serializedVersion: 6
m_ObjectHideFlags: 1
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: empty
m_Speed: 1
m_CycleOffset: 0
m_Transitions: []
m_StateMachineBehaviours: []
m_Position: {x: 50, y: 50, z: 0}
m_IKOnFeet: 0
m_WriteDefaultValues: 1
m_Mirror: 0
m_SpeedParameterActive: 0
m_MirrorParameterActive: 0
m_CycleOffsetParameterActive: 0
m_TimeParameterActive: 0
m_Motion: {fileID: 7400000, guid: 931318d79958463468b9ca3d48c96186, type: 2}
m_Tag:
m_SpeedParameter:
m_MirrorParameter:
m_CycleOffsetParameter:
m_TimeParameter:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 9aedd84d3acd0db4384c04f9b136ecb1
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 9100000
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,53 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!74 &7400000
AnimationClip:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: empty
serializedVersion: 7
m_Legacy: 0
m_Compressed: 0
m_UseHighQualityCurve: 1
m_RotationCurves: []
m_CompressedRotationCurves: []
m_EulerCurves: []
m_PositionCurves: []
m_ScaleCurves: []
m_FloatCurves: []
m_PPtrCurves: []
m_SampleRate: 60
m_WrapMode: 0
m_Bounds:
m_Center: {x: 0, y: 0, z: 0}
m_Extent: {x: 0, y: 0, z: 0}
m_ClipBindingConstant:
genericBindings: []
pptrCurveMapping: []
m_AnimationClipSettings:
serializedVersion: 2
m_AdditiveReferencePoseClip: {fileID: 0}
m_AdditiveReferencePoseTime: 0
m_StartTime: 0
m_StopTime: 1
m_OrientationOffsetY: 0
m_Level: 0
m_CycleOffset: 0
m_HasAdditiveReferencePose: 0
m_LoopTime: 0
m_LoopBlend: 0
m_LoopBlendOrientation: 0
m_LoopBlendPositionY: 0
m_LoopBlendPositionXZ: 0
m_KeepOriginalOrientation: 0
m_KeepOriginalPositionY: 1
m_KeepOriginalPositionXZ: 0
m_HeightFromFeet: 0
m_Mirror: 0
m_EditorCurves: []
m_EulerEditorCurves: []
m_HasGenericRootTransform: 0
m_HasMotionFloatCurves: 0
m_Events: []

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 931318d79958463468b9ca3d48c96186
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 7400000
userData:
assetBundleName:
assetBundleVariant:

View File

@ -2,6 +2,7 @@
using System;
using System.Linq;
using nadena.dev.modular_avatar.animation;
using nadena.dev.modular_avatar.core;
using nadena.dev.modular_avatar.core.editor;
using NUnit.Framework;
@ -10,6 +11,7 @@ using UnityEditor.Animations;
using UnityEngine;
using VRC.SDK3.Avatars.Components;
using AvatarProcessor = nadena.dev.ndmf.AvatarProcessor;
#pragma warning disable CS0618 // Type or member is obsolete
namespace modular_avatar_tests
{
@ -96,6 +98,28 @@ namespace modular_avatar_tests
AnimationTestUtil.AssertAnimationHasPath(((BlendTree)motion.children[0].motion).children[0].motion as AnimationClip, "child2/a");
}
[Test]
public void SupportsMergingMotions()
{
AnimationClip clip = new AnimationClip();
clip.name = "test clip";
var root = CreateRoot("root");
var c1 = CreateChild(root, "child1");
var mergeComponent = c1.AddComponent<ModularAvatarMergeBlendTree>();
mergeComponent.Motion = clip;
mergeComponent.PathMode = MergeAnimatorPathMode.Relative;
mergeComponent.RelativePathRoot.referencePath = "child2";
CreateChild(c1, "a");
AvatarProcessor.ProcessAvatar(root);
var fx = findFxLayer(root, MergeBlendTreePass.BlendTreeLayerName);
var motion = fx.stateMachine.states[0].state.motion as BlendTree;
Assert.IsTrue(motion!.children.Any(m => m.motion.name == clip.name));
}
[Test]
public void MergeOrderTest()
{
@ -115,7 +139,50 @@ namespace modular_avatar_tests
var layerNames = (FindController(root, VRCAvatarDescriptor.AnimLayerType.FX).animatorController as AnimatorController)
.layers.Select(l => l.name).ToArray();
Assert.AreEqual(new[] {MergeBlendTreePass.BlendTreeLayerName, "m2", "Eyes", "FaceMood", "m1", "m3"}, layerNames);
Assert.AreEqual(new[] {MergeBlendTreePass.BlendTreeLayerName, MMDRelayPass.ControlLayerName, MMDRelayPass.DummyLayerName, "m2", "Eyes", "FaceMood", "m1", "m3"}, layerNames);
}
[Test]
public void BoolParameterConvertedToFloat()
{
// Create an animator controller with a bool parameter
var controller = new AnimatorController();
controller.AddParameter("testBool", AnimatorControllerParameterType.Bool);
// Create the root object and set the FX layer to the created controller
var root = CreateRoot("root");
var vrcDesc = root.GetComponent<VRCAvatarDescriptor>();
var baseLayers = vrcDesc.baseAnimationLayers;
for (int i = 0; i < baseLayers.Length; i++)
{
if (baseLayers[i].type == VRCAvatarDescriptor.AnimLayerType.FX)
{
baseLayers[i].animatorController = controller;
baseLayers[i].isDefault = false;
}
}
vrcDesc.customizeAnimationLayers = true;
// Add a Merge Blend Tree component using the same parameter
var child = CreateChild(root, "child");
var mergeComponent = child.AddComponent<ModularAvatarMergeBlendTree>();
var blendTree = new BlendTree
{
blendParameter = "testBool",
blendType = BlendTreeType.Simple1D
};
blendTree.AddChild(AnimationTestUtil.AnimationWithPath("a"));
mergeComponent.BlendTree = blendTree;
// Process the avatar
AvatarProcessor.ProcessAvatar(root);
// Verify that the parameter is converted to a float
var fxController = FindController(root, VRCAvatarDescriptor.AnimLayerType.FX).animatorController as AnimatorController;
Assert.IsTrue(fxController!.parameters.Any(p =>
p.name == "testBool" && p.type == AnimatorControllerParameterType.Float));
}
ModularAvatarMergeAnimator TestMerge(GameObject root, string mergeName, Motion motion = null)

View File

@ -1,6 +1,7 @@
#if MA_VRCSDK3_AVATARS
using System.Linq;
using nadena.dev.modular_avatar.animation;
using nadena.dev.ndmf;
using NUnit.Framework;
using UnityEditor.Animations;
@ -24,7 +25,7 @@ namespace modular_avatar_tests
Assert.AreEqual(new []
{
"1", "2", "3", "4", "5"
"1", MMDRelayPass.ControlLayerName, MMDRelayPass.DummyLayerName, "2", "3", "4", "5"
}, layerNames);
}
}

View File

@ -1,8 +1,13 @@
#if MA_VRCSDK3_AVATARS
using nadena.dev.modular_avatar.animation;
using nadena.dev.modular_avatar.core.editor;
using nadena.dev.ndmf;
using nadena.dev.ndmf.animator;
using NUnit.Framework;
using UnityEngine;
using VRC.SDK3.Dynamics.PhysBone.Components;
using AvatarProcessor = nadena.dev.modular_avatar.core.editor.AvatarProcessor;
namespace modular_avatar_tests.DuplicatePBStripping
{
@ -66,6 +71,84 @@ namespace modular_avatar_tests.DuplicatePBStripping
// They should not be merged to preserve intentionally attached PhysBone, which is not copied from the avatar.
Assert.AreEqual(2, prefab.GetComponentsInChildren<VRCPhysBone>().Length);
}
[Test]
public void AcceptsHumanoidPB_OnTipBones()
{
var prefab = CreatePrefab("DuplicatePBStripping_HumanoidTip.prefab");
AvatarProcessor.ProcessAvatar(prefab);
var head = prefab.transform.Find("Armature/Hips/Spine/Chest/Neck/Head");
Transform subHead = null;
foreach (Transform t in head)
{
if (t.gameObject.name.StartsWith("Head$"))
{
subHead = t;
break;
}
}
Assert.NotNull(subHead);
Assert.AreEqual(1, subHead.childCount);
Assert.IsTrue(subHead.TryGetComponent<VRCPhysBone>(out _));
}
[Test]
public void RejectsHumanoidPB_OnInnerBones()
{
var prefab = CreatePrefab("DuplicatePBStripping_HumanoidInner.prefab");
var context = CreateContext(prefab);
context.ActivateExtensionContext<ModularAvatarContext>();
context.ActivateExtensionContextRecursive<AnimatorServicesContext>();
var errors = ErrorReport.CaptureErrors(() => new MergeArmatureHook().OnPreprocessAvatar(context, prefab));
Assert.AreEqual(1, errors.Count);
var error = errors[0];
Assert.AreEqual("error.merge_armature.physbone_on_humanoid_bone", ((SimpleError)error.TheError).TitleKey);
}
[Test]
public void AcceptsHumanoidPB_OnInnerBones_WithPBIgnores()
{
var prefab = CreatePrefab("DuplicatePBStripping_HumanoidInner_Ignored.prefab");
AssertInnerBones(prefab);
}
[Test]
public void AcceptsHumanoidPB_OnInnerBones_WithPBBlocker()
{
var prefab = CreatePrefab("DuplicatePBStripping_HumanoidInner_PBBlocker.prefab");
AssertInnerBones(prefab);
}
private static void AssertInnerBones(GameObject prefab)
{
var errors = ErrorReport.CaptureErrors(() => AvatarProcessor.ProcessAvatar(prefab));
Assert.AreEqual(0, errors.Count);
var hips = prefab.transform.Find("Armature/Hips");
Transform subHips = null;
foreach (Transform t in hips)
{
if (t.gameObject.name.StartsWith("Hips"))
{
subHips = t;
break;
}
}
Assert.NotNull(subHips);
Assert.AreEqual(1, subHips.childCount);
Assert.IsTrue(subHips.GetChild(0).name.StartsWith("New Child"));
Assert.IsTrue(subHips.TryGetComponent<VRCPhysBone>(out _));
}
}
}

View File

@ -0,0 +1,451 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &2498125727964202215
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 8637901343924930275}
m_Layer: 0
m_Name: UpperLeg.R
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &8637901343924930275
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2498125727964202215}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 2425011545215011340}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &5171819189215563704
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 5460633315343405867}
m_Layer: 0
m_Name: Spine
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &5460633315343405867
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5171819189215563704}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 2425011545215011340}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &5183706771555486972
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 696974841882562921}
m_Layer: 0
m_Name: New Child
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &696974841882562921
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5183706771555486972}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 2425011545215011340}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &5761571479978658530
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 3658090810984334700}
- component: {fileID: 8534621584560104554}
m_Layer: 0
m_Name: ToMerge
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &3658090810984334700
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5761571479978658530}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 2425011545215011340}
m_Father: {fileID: 6625593713945014388}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &8534621584560104554
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5761571479978658530}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 2df373bf91cf30b4bbd495e11cb1a2ec, type: 3}
m_Name:
m_EditorClassIdentifier:
mergeTarget:
referencePath: Armature
targetObject: {fileID: 6625593713945439624}
prefix:
suffix:
legacyLocked: 0
LockMode: 2
mangleNames: 1
--- !u!1 &8318249430048328751
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 2425011545215011340}
- component: {fileID: 116145570166396143}
m_Layer: 0
m_Name: Hips
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &2425011545215011340
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 8318249430048328751}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 5460633315343405867}
- {fileID: 3260084934125770558}
- {fileID: 8637901343924930275}
- {fileID: 696974841882562921}
m_Father: {fileID: 3658090810984334700}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &116145570166396143
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 8318249430048328751}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 1661641543, guid: 2a2c05204084d904aa4945ccff20d8e5, type: 3}
m_Name:
m_EditorClassIdentifier:
foldout_transforms: 1
foldout_forces: 1
foldout_collision: 1
foldout_stretchsquish: 1
foldout_limits: 1
foldout_grabpose: 1
foldout_options: 1
foldout_gizmos: 0
version: 1
integrationType: 0
rootTransform: {fileID: 0}
ignoreTransforms: []
endpointPosition: {x: 0, y: 0, z: 0}
multiChildType: 0
pull: 0.2
pullCurve:
serializedVersion: 2
m_Curve: []
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
spring: 0.2
springCurve:
serializedVersion: 2
m_Curve: []
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
stiffness: 0.2
stiffnessCurve:
serializedVersion: 2
m_Curve: []
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
gravity: 0
gravityCurve:
serializedVersion: 2
m_Curve: []
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
gravityFalloff: 0
gravityFalloffCurve:
serializedVersion: 2
m_Curve: []
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
immobileType: 0
immobile: 0
immobileCurve:
serializedVersion: 2
m_Curve: []
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
allowCollision: 1
collisionFilter:
allowSelf: 1
allowOthers: 1
radius: 0
radiusCurve:
serializedVersion: 2
m_Curve: []
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
colliders: []
limitType: 0
maxAngleX: 45
maxAngleXCurve:
serializedVersion: 2
m_Curve: []
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
maxAngleZ: 45
maxAngleZCurve:
serializedVersion: 2
m_Curve: []
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
limitRotation: {x: 0, y: 0, z: 0}
limitRotationXCurve:
serializedVersion: 2
m_Curve: []
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
limitRotationYCurve:
serializedVersion: 2
m_Curve: []
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
limitRotationZCurve:
serializedVersion: 2
m_Curve: []
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
allowGrabbing: 1
grabFilter:
allowSelf: 1
allowOthers: 1
allowPosing: 1
poseFilter:
allowSelf: 1
allowOthers: 1
snapToHand: 0
grabMovement: 0.5
maxStretch: 0
maxStretchCurve:
serializedVersion: 2
m_Curve: []
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
maxSquish: 0
maxSquishCurve:
serializedVersion: 2
m_Curve: []
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
stretchMotion: 0
stretchMotionCurve:
serializedVersion: 2
m_Curve: []
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
isAnimated: 0
resetWhenDisabled: 0
parameter:
showGizmos: 1
boneOpacity: 0.5
limitOpacity: 0.5
--- !u!1 &8784829580641167551
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 3260084934125770558}
m_Layer: 0
m_Name: UpperLeg.L
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &3260084934125770558
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 8784829580641167551}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 2425011545215011340}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1001 &4779359370445923223
PrefabInstance:
m_ObjectHideFlags: 0
serializedVersion: 2
m_Modification:
serializedVersion: 3
m_TransformParent: {fileID: 0}
m_Modifications:
- target: {fileID: 1846867717766401987, guid: 5fc34bdb40b2180438fb287e87d752cd,
type: 3}
propertyPath: m_Name
value: DuplicatePBStripping_HumanoidInner
objectReference: {fileID: 0}
- target: {fileID: 1846867717766632419, guid: 5fc34bdb40b2180438fb287e87d752cd,
type: 3}
propertyPath: m_LocalPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1846867717766632419, guid: 5fc34bdb40b2180438fb287e87d752cd,
type: 3}
propertyPath: m_LocalPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1846867717766632419, guid: 5fc34bdb40b2180438fb287e87d752cd,
type: 3}
propertyPath: m_LocalPosition.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1846867717766632419, guid: 5fc34bdb40b2180438fb287e87d752cd,
type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: 1846867717766632419, guid: 5fc34bdb40b2180438fb287e87d752cd,
type: 3}
propertyPath: m_LocalRotation.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1846867717766632419, guid: 5fc34bdb40b2180438fb287e87d752cd,
type: 3}
propertyPath: m_LocalRotation.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1846867717766632419, guid: 5fc34bdb40b2180438fb287e87d752cd,
type: 3}
propertyPath: m_LocalRotation.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1846867717766632419, guid: 5fc34bdb40b2180438fb287e87d752cd,
type: 3}
propertyPath: m_LocalEulerAnglesHint.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1846867717766632419, guid: 5fc34bdb40b2180438fb287e87d752cd,
type: 3}
propertyPath: m_LocalEulerAnglesHint.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1846867717766632419, guid: 5fc34bdb40b2180438fb287e87d752cd,
type: 3}
propertyPath: m_LocalEulerAnglesHint.z
value: 0
objectReference: {fileID: 0}
m_RemovedComponents: []
m_RemovedGameObjects: []
m_AddedGameObjects:
- targetCorrespondingSourceObject: {fileID: 1846867717766632419, guid: 5fc34bdb40b2180438fb287e87d752cd,
type: 3}
insertIndex: -1
addedObject: {fileID: 3658090810984334700}
m_AddedComponents: []
m_SourcePrefab: {fileID: 100100000, guid: 5fc34bdb40b2180438fb287e87d752cd, type: 3}
--- !u!4 &6625593713945014388 stripped
Transform:
m_CorrespondingSourceObject: {fileID: 1846867717766632419, guid: 5fc34bdb40b2180438fb287e87d752cd,
type: 3}
m_PrefabInstance: {fileID: 4779359370445923223}
m_PrefabAsset: {fileID: 0}
--- !u!1 &6625593713945439624 stripped
GameObject:
m_CorrespondingSourceObject: {fileID: 1846867717766401567, guid: 5fc34bdb40b2180438fb287e87d752cd,
type: 3}
m_PrefabInstance: {fileID: 4779359370445923223}
m_PrefabAsset: {fileID: 0}

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: b64134bbe3efa51449776e476b920317
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,108 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1001 &3314855663531197346
PrefabInstance:
m_ObjectHideFlags: 0
serializedVersion: 2
m_Modification:
serializedVersion: 3
m_TransformParent: {fileID: 0}
m_Modifications:
- target: {fileID: 116145570166396143, guid: b64134bbe3efa51449776e476b920317,
type: 3}
propertyPath: ignoreTransforms.Array.size
value: 3
objectReference: {fileID: 0}
- target: {fileID: 116145570166396143, guid: b64134bbe3efa51449776e476b920317,
type: 3}
propertyPath: ignoreTransforms.Array.data[0]
value:
objectReference: {fileID: 7334299701829505161}
- target: {fileID: 116145570166396143, guid: b64134bbe3efa51449776e476b920317,
type: 3}
propertyPath: ignoreTransforms.Array.data[1]
value:
objectReference: {fileID: 233798298552718492}
- target: {fileID: 116145570166396143, guid: b64134bbe3efa51449776e476b920317,
type: 3}
propertyPath: ignoreTransforms.Array.data[2]
value:
objectReference: {fileID: 6475971928874796353}
- target: {fileID: 6625593713945014388, guid: b64134bbe3efa51449776e476b920317,
type: 3}
propertyPath: m_LocalPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 6625593713945014388, guid: b64134bbe3efa51449776e476b920317,
type: 3}
propertyPath: m_LocalPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 6625593713945014388, guid: b64134bbe3efa51449776e476b920317,
type: 3}
propertyPath: m_LocalPosition.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 6625593713945014388, guid: b64134bbe3efa51449776e476b920317,
type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: 6625593713945014388, guid: b64134bbe3efa51449776e476b920317,
type: 3}
propertyPath: m_LocalRotation.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 6625593713945014388, guid: b64134bbe3efa51449776e476b920317,
type: 3}
propertyPath: m_LocalRotation.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 6625593713945014388, guid: b64134bbe3efa51449776e476b920317,
type: 3}
propertyPath: m_LocalRotation.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 6625593713945014388, guid: b64134bbe3efa51449776e476b920317,
type: 3}
propertyPath: m_LocalEulerAnglesHint.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 6625593713945014388, guid: b64134bbe3efa51449776e476b920317,
type: 3}
propertyPath: m_LocalEulerAnglesHint.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 6625593713945014388, guid: b64134bbe3efa51449776e476b920317,
type: 3}
propertyPath: m_LocalEulerAnglesHint.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 6625593713945439316, guid: b64134bbe3efa51449776e476b920317,
type: 3}
propertyPath: m_Name
value: DuplicatePBStripping_HumanoidInner_Ignored
objectReference: {fileID: 0}
m_RemovedComponents: []
m_RemovedGameObjects: []
m_AddedGameObjects: []
m_AddedComponents: []
m_SourcePrefab: {fileID: 100100000, guid: b64134bbe3efa51449776e476b920317, type: 3}
--- !u!4 &233798298552718492 stripped
Transform:
m_CorrespondingSourceObject: {fileID: 3260084934125770558, guid: b64134bbe3efa51449776e476b920317,
type: 3}
m_PrefabInstance: {fileID: 3314855663531197346}
m_PrefabAsset: {fileID: 0}
--- !u!4 &6475971928874796353 stripped
Transform:
m_CorrespondingSourceObject: {fileID: 8637901343924930275, guid: b64134bbe3efa51449776e476b920317,
type: 3}
m_PrefabInstance: {fileID: 3314855663531197346}
m_PrefabAsset: {fileID: 0}
--- !u!4 &7334299701829505161 stripped
Transform:
m_CorrespondingSourceObject: {fileID: 5460633315343405867, guid: b64134bbe3efa51449776e476b920317,
type: 3}
m_PrefabInstance: {fileID: 3314855663531197346}
m_PrefabAsset: {fileID: 0}

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 52a2875b9b43d1047a7bc3a9d4613edd
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,136 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1001 &8692883387518570274
PrefabInstance:
m_ObjectHideFlags: 0
serializedVersion: 2
m_Modification:
serializedVersion: 3
m_TransformParent: {fileID: 0}
m_Modifications:
- target: {fileID: 6625593713945014388, guid: b64134bbe3efa51449776e476b920317,
type: 3}
propertyPath: m_LocalPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 6625593713945014388, guid: b64134bbe3efa51449776e476b920317,
type: 3}
propertyPath: m_LocalPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 6625593713945014388, guid: b64134bbe3efa51449776e476b920317,
type: 3}
propertyPath: m_LocalPosition.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 6625593713945014388, guid: b64134bbe3efa51449776e476b920317,
type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: 6625593713945014388, guid: b64134bbe3efa51449776e476b920317,
type: 3}
propertyPath: m_LocalRotation.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 6625593713945014388, guid: b64134bbe3efa51449776e476b920317,
type: 3}
propertyPath: m_LocalRotation.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 6625593713945014388, guid: b64134bbe3efa51449776e476b920317,
type: 3}
propertyPath: m_LocalRotation.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 6625593713945014388, guid: b64134bbe3efa51449776e476b920317,
type: 3}
propertyPath: m_LocalEulerAnglesHint.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 6625593713945014388, guid: b64134bbe3efa51449776e476b920317,
type: 3}
propertyPath: m_LocalEulerAnglesHint.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 6625593713945014388, guid: b64134bbe3efa51449776e476b920317,
type: 3}
propertyPath: m_LocalEulerAnglesHint.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 6625593713945439316, guid: b64134bbe3efa51449776e476b920317,
type: 3}
propertyPath: m_Name
value: DuplicatePBStripping_HumanoidInner_PBBlocker
objectReference: {fileID: 0}
m_RemovedComponents: []
m_RemovedGameObjects: []
m_AddedGameObjects: []
m_AddedComponents:
- targetCorrespondingSourceObject: {fileID: 5171819189215563704, guid: b64134bbe3efa51449776e476b920317,
type: 3}
insertIndex: -1
addedObject: {fileID: 9202998116771530898}
- targetCorrespondingSourceObject: {fileID: 8784829580641167551, guid: b64134bbe3efa51449776e476b920317,
type: 3}
insertIndex: -1
addedObject: {fileID: 4756456952176026372}
- targetCorrespondingSourceObject: {fileID: 2498125727964202215, guid: b64134bbe3efa51449776e476b920317,
type: 3}
insertIndex: -1
addedObject: {fileID: 2534654980684605449}
m_SourcePrefab: {fileID: 100100000, guid: b64134bbe3efa51449776e476b920317, type: 3}
--- !u!1 &93072112910444445 stripped
GameObject:
m_CorrespondingSourceObject: {fileID: 8784829580641167551, guid: b64134bbe3efa51449776e476b920317,
type: 3}
m_PrefabInstance: {fileID: 8692883387518570274}
m_PrefabAsset: {fileID: 0}
--- !u!114 &4756456952176026372
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 93072112910444445}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: a5bf908a199a4648845ebe2fd3b5a4bd, type: 3}
m_Name:
m_EditorClassIdentifier:
--- !u!1 &4568529383833092250 stripped
GameObject:
m_CorrespondingSourceObject: {fileID: 5171819189215563704, guid: b64134bbe3efa51449776e476b920317,
type: 3}
m_PrefabInstance: {fileID: 8692883387518570274}
m_PrefabAsset: {fileID: 0}
--- !u!114 &9202998116771530898
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4568529383833092250}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: a5bf908a199a4648845ebe2fd3b5a4bd, type: 3}
m_Name:
m_EditorClassIdentifier:
--- !u!1 &6487562254561725381 stripped
GameObject:
m_CorrespondingSourceObject: {fileID: 2498125727964202215, guid: b64134bbe3efa51449776e476b920317,
type: 3}
m_PrefabInstance: {fileID: 8692883387518570274}
m_PrefabAsset: {fileID: 0}
--- !u!114 &2534654980684605449
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6487562254561725381}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: a5bf908a199a4648845ebe2fd3b5a4bd, type: 3}
m_Name:
m_EditorClassIdentifier:

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 16772fc19ae8e7b49ab1e94f98420181
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,483 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &153081034637439403
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 7524471747194580000}
- component: {fileID: 8200741828756418565}
m_Layer: 0
m_Name: ToMerge
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &7524471747194580000
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 153081034637439403}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 1962984382521366047}
m_Father: {fileID: 1923677775196482311}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &8200741828756418565
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 153081034637439403}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 2df373bf91cf30b4bbd495e11cb1a2ec, type: 3}
m_Name:
m_EditorClassIdentifier:
mergeTarget:
referencePath: Armature
targetObject: {fileID: 1923677775196190459}
prefix:
suffix:
legacyLocked: 0
LockMode: 2
mangleNames: 1
--- !u!1 &645148391116447186
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 2027561760184575219}
m_Layer: 0
m_Name: Child
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &2027561760184575219
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 645148391116447186}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 6717659006790879614}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &1399796362742295232
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 6717659006790879614}
- component: {fileID: 2194555605237480662}
m_Layer: 0
m_Name: Head
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &6717659006790879614
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1399796362742295232}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 2027561760184575219}
m_Father: {fileID: 3066136301200089550}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &2194555605237480662
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1399796362742295232}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 1661641543, guid: 2a2c05204084d904aa4945ccff20d8e5, type: 3}
m_Name:
m_EditorClassIdentifier:
foldout_transforms: 1
foldout_forces: 1
foldout_collision: 1
foldout_stretchsquish: 1
foldout_limits: 1
foldout_grabpose: 1
foldout_options: 1
foldout_gizmos: 0
version: 1
integrationType: 0
rootTransform: {fileID: 0}
ignoreTransforms: []
endpointPosition: {x: 0, y: 0, z: 0}
multiChildType: 0
pull: 0.2
pullCurve:
serializedVersion: 2
m_Curve: []
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
spring: 0.2
springCurve:
serializedVersion: 2
m_Curve: []
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
stiffness: 0.2
stiffnessCurve:
serializedVersion: 2
m_Curve: []
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
gravity: 0
gravityCurve:
serializedVersion: 2
m_Curve: []
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
gravityFalloff: 0
gravityFalloffCurve:
serializedVersion: 2
m_Curve: []
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
immobileType: 0
immobile: 0
immobileCurve:
serializedVersion: 2
m_Curve: []
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
allowCollision: 1
collisionFilter:
allowSelf: 1
allowOthers: 1
radius: 0
radiusCurve:
serializedVersion: 2
m_Curve: []
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
colliders: []
limitType: 0
maxAngleX: 45
maxAngleXCurve:
serializedVersion: 2
m_Curve: []
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
maxAngleZ: 45
maxAngleZCurve:
serializedVersion: 2
m_Curve: []
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
limitRotation: {x: 0, y: 0, z: 0}
limitRotationXCurve:
serializedVersion: 2
m_Curve: []
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
limitRotationYCurve:
serializedVersion: 2
m_Curve: []
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
limitRotationZCurve:
serializedVersion: 2
m_Curve: []
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
allowGrabbing: 1
grabFilter:
allowSelf: 1
allowOthers: 1
allowPosing: 1
poseFilter:
allowSelf: 1
allowOthers: 1
snapToHand: 0
grabMovement: 0.5
maxStretch: 0
maxStretchCurve:
serializedVersion: 2
m_Curve: []
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
maxSquish: 0
maxSquishCurve:
serializedVersion: 2
m_Curve: []
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
stretchMotion: 0
stretchMotionCurve:
serializedVersion: 2
m_Curve: []
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
isAnimated: 0
resetWhenDisabled: 0
parameter:
showGizmos: 1
boneOpacity: 0.5
limitOpacity: 0.5
--- !u!1 &4263254571135048414
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 8819743074213097153}
m_Layer: 0
m_Name: Chest
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &8819743074213097153
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4263254571135048414}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 3066136301200089550}
m_Father: {fileID: 7352385770120952471}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &4581483200136452596
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 3066136301200089550}
m_Layer: 0
m_Name: Neck
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &3066136301200089550
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4581483200136452596}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 6717659006790879614}
m_Father: {fileID: 8819743074213097153}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &7424539437707308133
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 1962984382521366047}
m_Layer: 0
m_Name: Hips
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &1962984382521366047
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 7424539437707308133}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 7352385770120952471}
m_Father: {fileID: 7524471747194580000}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &7957102078560458882
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 7352385770120952471}
m_Layer: 0
m_Name: Spine
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &7352385770120952471
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 7957102078560458882}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 8819743074213097153}
m_Father: {fileID: 1962984382521366047}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1001 &221559126042065124
PrefabInstance:
m_ObjectHideFlags: 0
serializedVersion: 2
m_Modification:
serializedVersion: 3
m_TransformParent: {fileID: 0}
m_Modifications:
- target: {fileID: 1846867717766401987, guid: 5fc34bdb40b2180438fb287e87d752cd,
type: 3}
propertyPath: m_Name
value: DuplicatePBStripping_HumanoidTip
objectReference: {fileID: 0}
- target: {fileID: 1846867717766632419, guid: 5fc34bdb40b2180438fb287e87d752cd,
type: 3}
propertyPath: m_LocalPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1846867717766632419, guid: 5fc34bdb40b2180438fb287e87d752cd,
type: 3}
propertyPath: m_LocalPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1846867717766632419, guid: 5fc34bdb40b2180438fb287e87d752cd,
type: 3}
propertyPath: m_LocalPosition.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1846867717766632419, guid: 5fc34bdb40b2180438fb287e87d752cd,
type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: 1846867717766632419, guid: 5fc34bdb40b2180438fb287e87d752cd,
type: 3}
propertyPath: m_LocalRotation.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1846867717766632419, guid: 5fc34bdb40b2180438fb287e87d752cd,
type: 3}
propertyPath: m_LocalRotation.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1846867717766632419, guid: 5fc34bdb40b2180438fb287e87d752cd,
type: 3}
propertyPath: m_LocalRotation.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1846867717766632419, guid: 5fc34bdb40b2180438fb287e87d752cd,
type: 3}
propertyPath: m_LocalEulerAnglesHint.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1846867717766632419, guid: 5fc34bdb40b2180438fb287e87d752cd,
type: 3}
propertyPath: m_LocalEulerAnglesHint.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 1846867717766632419, guid: 5fc34bdb40b2180438fb287e87d752cd,
type: 3}
propertyPath: m_LocalEulerAnglesHint.z
value: 0
objectReference: {fileID: 0}
m_RemovedComponents: []
m_RemovedGameObjects: []
m_AddedGameObjects:
- targetCorrespondingSourceObject: {fileID: 1846867717766632419, guid: 5fc34bdb40b2180438fb287e87d752cd,
type: 3}
insertIndex: -1
addedObject: {fileID: 7524471747194580000}
m_AddedComponents: []
m_SourcePrefab: {fileID: 100100000, guid: 5fc34bdb40b2180438fb287e87d752cd, type: 3}
--- !u!1 &1923677775196190459 stripped
GameObject:
m_CorrespondingSourceObject: {fileID: 1846867717766401567, guid: 5fc34bdb40b2180438fb287e87d752cd,
type: 3}
m_PrefabInstance: {fileID: 221559126042065124}
m_PrefabAsset: {fileID: 0}
--- !u!4 &1923677775196482311 stripped
Transform:
m_CorrespondingSourceObject: {fileID: 1846867717766632419, guid: 5fc34bdb40b2180438fb287e87d752cd,
type: 3}
m_PrefabInstance: {fileID: 221559126042065124}
m_PrefabAsset: {fileID: 0}

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: b615cc5447c44314994b575a22200863
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -23,12 +23,13 @@ Transform:
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 43397333450003214}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 5388524103681595368}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &709712915065668132
GameObject:
@ -55,14 +56,15 @@ Transform:
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 709712915065668132}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: -0.9999927, y: -0.76461804, z: -2.4018843}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 8923018049112000952}
- {fileID: 8346263645556903402}
m_Father: {fileID: 0}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &4446924385526016477
MonoBehaviour:
@ -365,13 +367,14 @@ Transform:
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 3294938996247584563}
serializedVersion: 2
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0.0011}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 2300981236930770838}
m_Father: {fileID: 4839204755409456256}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &356280997442785920
MonoBehaviour:
@ -548,12 +551,13 @@ Transform:
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4932326906014275043}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 1450078349704776806}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &5343281448102039389
GameObject:
@ -579,13 +583,14 @@ Transform:
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5343281448102039389}
serializedVersion: 2
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 6824962001568238675}
m_Father: {fileID: 8923018049112000952}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &8084613166182812076
MonoBehaviour:
@ -763,13 +768,14 @@ Transform:
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 6020944473552814992}
serializedVersion: 2
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 5388524103681595368}
m_Father: {fileID: 8346263645556903402}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &6799239616120235895
MonoBehaviour:
@ -785,6 +791,7 @@ MonoBehaviour:
m_EditorClassIdentifier:
mergeTarget:
referencePath: Armature
targetObject: {fileID: 0}
prefix:
suffix:
legacyLocked: 0
@ -813,13 +820,14 @@ Transform:
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 7021121575447504728}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 4839204755409456256}
m_Father: {fileID: 5531473902160065818}
m_RootOrder: 1
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &8147540163686070565
GameObject:
@ -844,11 +852,12 @@ Transform:
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 8147540163686070565}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 1450078349704776806}
m_Father: {fileID: 5531473902160065818}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}

View File

@ -23,13 +23,14 @@ Transform:
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5307695925281184}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 2470959523001346680}
m_Father: {fileID: 3288029844994708450}
m_RootOrder: 1
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &1185347276494512093
GameObject:
@ -54,15 +55,16 @@ Transform:
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 1185347276494512093}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 8466034055491725982}
- {fileID: 4920308331760759596}
- {fileID: 1681599259655281294}
m_Father: {fileID: 3288029844994708450}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &2671187349547250459
GameObject:
@ -87,12 +89,13 @@ Transform:
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 2671187349547250459}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 8466034055491725982}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &3118168415141652901
GameObject:
@ -117,13 +120,14 @@ Transform:
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 3118168415141652901}
serializedVersion: 2
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 4599847896342424235}
m_Father: {fileID: 1924794259696430912}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &3229473751376893384
GameObject:
@ -149,12 +153,13 @@ Transform:
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 3229473751376893384}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 1924794259696430912}
m_RootOrder: 1
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &1240230512864768401
MonoBehaviour:
@ -168,6 +173,15 @@ MonoBehaviour:
m_Script: {fileID: 1661641543, guid: 2a2c05204084d904aa4945ccff20d8e5, type: 3}
m_Name:
m_EditorClassIdentifier:
foldout_transforms: 1
foldout_forces: 1
foldout_collision: 1
foldout_stretchsquish: 1
foldout_limits: 1
foldout_grabpose: 1
foldout_options: 1
foldout_gizmos: 0
version: 0
integrationType: 0
rootTransform: {fileID: 8466034055491725982}
ignoreTransforms: []
@ -217,6 +231,9 @@ MonoBehaviour:
m_PostInfinity: 2
m_RotationOrder: 4
allowCollision: 1
collisionFilter:
allowSelf: 1
allowOthers: 1
radius: 0
radiusCurve:
serializedVersion: 2
@ -260,7 +277,14 @@ MonoBehaviour:
m_PostInfinity: 2
m_RotationOrder: 4
allowGrabbing: 1
grabFilter:
allowSelf: 1
allowOthers: 1
allowPosing: 1
poseFilter:
allowSelf: 1
allowOthers: 1
snapToHand: 0
grabMovement: 0.5
maxStretch: 0
maxStretchCurve:
@ -269,7 +293,22 @@ MonoBehaviour:
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
maxSquish: 0
maxSquishCurve:
serializedVersion: 2
m_Curve: []
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
stretchMotion: 0
stretchMotionCurve:
serializedVersion: 2
m_Curve: []
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
isAnimated: 0
resetWhenDisabled: 0
parameter:
showGizmos: 1
boneOpacity: 0.5
@ -298,15 +337,16 @@ Transform:
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 3669416188374771048}
serializedVersion: 2
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 3144974420888563984}
- {fileID: 1058366299372909130}
- {fileID: 3585740765715002245}
m_Father: {fileID: 1346911765870406418}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &4555694376538259855
MonoBehaviour:
@ -322,9 +362,12 @@ MonoBehaviour:
m_EditorClassIdentifier:
mergeTarget:
referencePath: Armature
targetObject: {fileID: 0}
prefix:
suffix:
locked: 0
legacyLocked: 0
LockMode: 2
mangleNames: 1
--- !u!1 &4762681010693511042
GameObject:
m_ObjectHideFlags: 0
@ -348,12 +391,13 @@ Transform:
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 4762681010693511042}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 2470959523001346680}
m_RootOrder: 2
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &5060562373779566306
GameObject:
@ -378,12 +422,13 @@ Transform:
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5060562373779566306}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 1924794259696430912}
m_RootOrder: 2
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &5538066357489875403
GameObject:
@ -408,13 +453,14 @@ Transform:
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 5538066357489875403}
serializedVersion: 2
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 9118779566147113326}
m_Father: {fileID: 2470959523001346680}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &7059671866930001398
GameObject:
@ -439,12 +485,13 @@ Transform:
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 7059671866930001398}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 3144974420888563984}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!1 &7546831960978351324
GameObject:
@ -471,14 +518,15 @@ Transform:
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 7546831960978351324}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: -0.9999927, y: -0.76461804, z: -2.4018843}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children:
- {fileID: 1924794259696430912}
- {fileID: 1346911765870406418}
m_Father: {fileID: 0}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &6689100707227635493
MonoBehaviour:
@ -506,6 +554,7 @@ MonoBehaviour:
unityVersion:
portraitCameraPositionOffset: {x: 0, y: 0, z: 0}
portraitCameraRotationOffset: {x: 0, y: 1, z: 0, w: -0.00000004371139}
networkIDs: []
customExpressions: 0
expressionsMenu: {fileID: 0}
expressionParameters: {fileID: 0}
@ -781,12 +830,13 @@ Transform:
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 8948347872370946622}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 2470959523001346680}
m_RootOrder: 1
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &5925503763981397634
MonoBehaviour:
@ -800,6 +850,15 @@ MonoBehaviour:
m_Script: {fileID: 1661641543, guid: 2a2c05204084d904aa4945ccff20d8e5, type: 3}
m_Name:
m_EditorClassIdentifier:
foldout_transforms: 1
foldout_forces: 1
foldout_collision: 1
foldout_stretchsquish: 1
foldout_limits: 1
foldout_grabpose: 1
foldout_options: 1
foldout_gizmos: 0
version: 0
integrationType: 0
rootTransform: {fileID: 3585740765715002245}
ignoreTransforms: []
@ -849,6 +908,9 @@ MonoBehaviour:
m_PostInfinity: 2
m_RotationOrder: 4
allowCollision: 1
collisionFilter:
allowSelf: 1
allowOthers: 1
radius: 0
radiusCurve:
serializedVersion: 2
@ -892,7 +954,14 @@ MonoBehaviour:
m_PostInfinity: 2
m_RotationOrder: 4
allowGrabbing: 1
grabFilter:
allowSelf: 1
allowOthers: 1
allowPosing: 1
poseFilter:
allowSelf: 1
allowOthers: 1
snapToHand: 0
grabMovement: 0.5
maxStretch: 0
maxStretchCurve:
@ -901,7 +970,22 @@ MonoBehaviour:
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
maxSquish: 0
maxSquishCurve:
serializedVersion: 2
m_Curve: []
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
stretchMotion: 0
stretchMotionCurve:
serializedVersion: 2
m_Curve: []
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
isAnimated: 0
resetWhenDisabled: 0
parameter:
showGizmos: 1
boneOpacity: 0.5
@ -918,6 +1002,15 @@ MonoBehaviour:
m_Script: {fileID: 1661641543, guid: 2a2c05204084d904aa4945ccff20d8e5, type: 3}
m_Name:
m_EditorClassIdentifier:
foldout_transforms: 1
foldout_forces: 1
foldout_collision: 1
foldout_stretchsquish: 1
foldout_limits: 1
foldout_grabpose: 1
foldout_options: 1
foldout_gizmos: 0
version: 0
integrationType: 0
rootTransform: {fileID: 3144974420888563984}
ignoreTransforms: []
@ -967,6 +1060,9 @@ MonoBehaviour:
m_PostInfinity: 2
m_RotationOrder: 4
allowCollision: 1
collisionFilter:
allowSelf: 1
allowOthers: 1
radius: 0
radiusCurve:
serializedVersion: 2
@ -1010,7 +1106,14 @@ MonoBehaviour:
m_PostInfinity: 2
m_RotationOrder: 4
allowGrabbing: 1
grabFilter:
allowSelf: 1
allowOthers: 1
allowPosing: 1
poseFilter:
allowSelf: 1
allowOthers: 1
snapToHand: 0
grabMovement: 0.5
maxStretch: 0
maxStretchCurve:
@ -1019,7 +1122,22 @@ MonoBehaviour:
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
maxSquish: 0
maxSquishCurve:
serializedVersion: 2
m_Curve: []
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
stretchMotion: 0
stretchMotionCurve:
serializedVersion: 2
m_Curve: []
m_PreInfinity: 2
m_PostInfinity: 2
m_RotationOrder: 4
isAnimated: 0
resetWhenDisabled: 0
parameter:
showGizmos: 1
boneOpacity: 0.5

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 0728ebdfdba1b344a9101097e4089eff
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 B

Some files were not shown because too many files have changed in this diff Show More