mirror of
https://github.com/bdunderscore/modular-avatar.git
synced 2025-04-12 23:48:59 +08:00
Compare commits
94 Commits
1.12.0-alp
...
main
Author | SHA1 | Date | |
---|---|---|---|
|
59c256704b | ||
|
c4f3728d5e | ||
|
dcda15569a | ||
|
8cba3560ce | ||
|
17051419ec | ||
|
1a1cae4e04 | ||
|
e5e4c41b38 | ||
|
c7c9e23acb | ||
|
5be1f13840 | ||
|
420f9b00b1 | ||
|
45b5db46c5 | ||
|
03ee9d6048 | ||
|
897d168137 | ||
|
400960257e | ||
|
f0fcbb66b1 | ||
|
7fd35bb49a | ||
|
bc4c6628ee | ||
|
b733ce2e4d | ||
|
3324d3f71b | ||
|
c3d2cfb29f | ||
|
7610020c3b | ||
|
89de978c77 | ||
|
db9389052c | ||
|
81aed5b798 | ||
|
706ce7aa2f | ||
|
b75e74ef84 | ||
|
8ef4cf6328 | ||
|
c521bd7721 | ||
|
e46e958f39 | ||
|
8a45515af0 | ||
|
36b442f904 | ||
|
124392c422 | ||
|
dff7f03c2f | ||
|
713a0d3b1d | ||
|
e2a02982d5 | ||
|
672dd8b31f | ||
|
6175e20e46 | ||
|
fce938820b | ||
|
34deac5681 | ||
|
b49e5cb460 | ||
|
3165d471b5 | ||
|
2d59c74066 | ||
|
55d744885f | ||
|
318d65f3b5 | ||
|
aac70873c5 | ||
|
5a17d6ea9a | ||
|
62fd986fd0 | ||
|
39b4df8367 | ||
|
fc9b2683c8 | ||
|
98311f11f8 | ||
|
2557972461 | ||
|
9510c56f7a | ||
|
9418b00b54 | ||
|
61f11ff836 | ||
|
2823696af9 | ||
|
45352296e9 | ||
|
4323b40362 | ||
|
57f1851cdd | ||
|
494ad1c4d9 | ||
|
2e79c9b195 | ||
|
7182baca47 | ||
|
71a0d82c66 | ||
|
4c44c576de | ||
|
ec73eb6225 | ||
|
295a46ec12 | ||
|
fa004b2db5 | ||
|
f6362cdbc2 | ||
|
cbf7fa4233 | ||
|
a7906e4fd6 | ||
|
f0a61fe55a | ||
|
7abfb021e3 | ||
|
903f230633 | ||
|
be729c8f53 | ||
|
233521b029 | ||
|
92ebc1c1ac | ||
|
1a20333b58 | ||
|
5f19bad688 | ||
|
fdd3110a98 | ||
|
c7a06e71a0 | ||
|
cd5bb5ff4e | ||
|
e91b8ab6c3 | ||
|
e3a01ff58b | ||
|
5de63b3495 | ||
|
1c8477ba4a | ||
|
cdf8d8400d | ||
|
aaa448bf57 | ||
|
e0f55ddc4f | ||
|
d4543a38c5 | ||
|
e471df8860 | ||
|
70dd38e970 | ||
|
7e5d631b9d | ||
|
3f57e17548 | ||
|
242a108703 | ||
|
07cce41329 |
14
.github/CHANGELOG-HEADER.md
vendored
Normal file
14
.github/CHANGELOG-HEADER.md
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
## [Unreleased]
|
||||
|
||||
### Added
|
||||
|
||||
### Fixed
|
||||
|
||||
### Changed
|
||||
|
||||
### Removed
|
||||
|
||||
### Security
|
||||
|
||||
### Deprecated
|
||||
|
4
.github/ProjectRoot/vpm-manifest-2022.json
vendored
4
.github/ProjectRoot/vpm-manifest-2022.json
vendored
@ -4,7 +4,7 @@
|
||||
"version": "3.7.4"
|
||||
},
|
||||
"nadena.dev.ndmf": {
|
||||
"version": "1.7.0-alpha.0"
|
||||
"version": "1.8.0-alpha.4"
|
||||
}
|
||||
},
|
||||
"locked": {
|
||||
@ -19,7 +19,7 @@
|
||||
"dependencies": {}
|
||||
},
|
||||
"nadena.dev.ndmf": {
|
||||
"version": "1.7.0-alpha.0"
|
||||
"version": "1.8.0-alpha.4"
|
||||
}
|
||||
}
|
||||
}
|
71
.github/cut-changelog.pl
vendored
Executable file
71
.github/cut-changelog.pl
vendored
Executable file
@ -0,0 +1,71 @@
|
||||
#!/usr/bin/perl
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
|
||||
my ($changelog_file, $header_file, $version, $excerpt_file) = @ARGV;
|
||||
|
||||
open my $changelog, '<', $changelog_file or die "Can't open $changelog_file: $!";
|
||||
open my $header, '<', $header_file or die "Can't open $header_file: $!";
|
||||
open my $new_changelog, '>', "$changelog_file.new" or die "Can't open $changelog_file.new: $!";
|
||||
|
||||
if (!$excerpt_file) {
|
||||
$excerpt_file = '/dev/null';
|
||||
}
|
||||
|
||||
open my $excerpt, '>', $excerpt_file or die "Can't open $excerpt_file: $!";
|
||||
|
||||
# Copy all lines before the first "## "
|
||||
while (my $line = <$changelog>) {
|
||||
last if $line =~ /^## /;
|
||||
print $new_changelog $line;
|
||||
}
|
||||
|
||||
# Copy header into the output changelog
|
||||
while (my $line = <$header>) {
|
||||
print $new_changelog $line;
|
||||
}
|
||||
|
||||
# Generate new header: ## [version] - [YYYY-mm-DD]
|
||||
|
||||
my $date = `date +%Y-%m-%d`;
|
||||
chomp $date;
|
||||
|
||||
print $new_changelog "## [$version] - [$date]\n";
|
||||
|
||||
# Copy all lines until the next ## into both the new changelog and $excerpt.
|
||||
# Prune any ###-sections that contain no content
|
||||
|
||||
my @buffered;
|
||||
|
||||
while (my $line = <$changelog>) {
|
||||
if ($line =~ /^### /) {
|
||||
@buffered = ($line);
|
||||
} elsif ($line =~ /^\s*$/) {
|
||||
if (@buffered) {
|
||||
push @buffered, $line;
|
||||
} else {
|
||||
print $new_changelog $line;
|
||||
print $excerpt $line;
|
||||
}
|
||||
} elsif ($line =~ /^## /) {
|
||||
@buffered = ();
|
||||
print $new_changelog $line;
|
||||
last;
|
||||
} else {
|
||||
for my $buffered_line (@buffered){
|
||||
print $new_changelog $buffered_line;
|
||||
print $excerpt $buffered_line;
|
||||
}
|
||||
@buffered = ();
|
||||
print $new_changelog $line;
|
||||
print $excerpt $line;
|
||||
}
|
||||
}
|
||||
|
||||
# Copy remainder of changelog into new changelog
|
||||
while (my $line = <$changelog>) {
|
||||
print $new_changelog $line;
|
||||
}
|
||||
|
||||
rename "$changelog_file.new", $changelog_file or die "Can't rename $changelog_file.new to $changelog_file: $!";
|
22
.github/gen-docs-changelog.pl
vendored
Executable file
22
.github/gen-docs-changelog.pl
vendored
Executable 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;
|
||||
}
|
91
.github/workflows/build-release.yml
vendored
91
.github/workflows/build-release.yml
vendored
@ -1,91 +0,0 @@
|
||||
name: Build Release
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
pull_request:
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
- refactor-structure
|
||||
tags:
|
||||
- '**'
|
||||
|
||||
env:
|
||||
packageName: "nadena.dev.modular-avatar"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Checkout logo assets
|
||||
uses: actions/checkout@v4
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
with:
|
||||
repository: bdunderscore/modular-avatar-images
|
||||
path: .github/image-assets
|
||||
- name: Inject logo assets
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
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
|
||||
id: semver-check
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
env:
|
||||
REF_NAME: ${{ github.ref }}
|
||||
run: |
|
||||
if echo $REF_NAME | grep '[a-z]-[0-9]' && ! echo $REF_NAME | grep '^refs/tags/1\.5\.0-'; then
|
||||
echo "Tag name does not follow semver prerelease syntax: $REF_NAME"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- name: get version
|
||||
id: version
|
||||
uses: notiz-dev/github-action-json-property@a5a9c668b16513c737c3e1f8956772c99c73f6e8
|
||||
with:
|
||||
path: "package.json"
|
||||
prop_path: "version"
|
||||
|
||||
- name: Check tag consistency
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
run: |
|
||||
if [ "${{ steps.version.outputs.prop }}" != "${GITHUB_REF##*/}" ]; then
|
||||
echo "Version in package.json does not match tag name: ${{ steps.version.outputs.prop }} != ${GITHUB_REF##*/}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
- run: echo ${{steps.version.outputs.prop}}
|
||||
|
||||
- name: Set Environment Variables
|
||||
run: |
|
||||
echo "zipFile=${{ env.packageName }}-${{ steps.version.outputs.prop }}".zip >> $GITHUB_ENV
|
||||
echo "zipFileSHA256=${{ env.packageName }}-${{ steps.version.outputs.prop }}".zip.sha256 >> $GITHUB_ENV
|
||||
echo "unityPackage=${{ env.packageName }}-${{ steps.version.outputs.prop }}.unitypackage" >> $GITHUB_ENV
|
||||
|
||||
- name: Create Zip
|
||||
run: |
|
||||
zip ".github/${{env.zipFile}}" ./* -r -x .github .git '.git/*' '*~/*' '*.ps1*'
|
||||
mv ".github/${{env.zipFile}}" "${{env.zipFile}}"
|
||||
sha256sum "${{env.zipFile}}" > "${{env.zipFileSHA256}}"
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: package-zip
|
||||
path: ${{ env.zipFile }}
|
||||
|
||||
- name: Make Release
|
||||
uses: softprops/action-gh-release@c95fe1489396fe8a9eb87c0abf8aa5b2ef267fda
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
with:
|
||||
draft: true
|
||||
generate_release_notes: true
|
||||
tag_name: ${{ steps.version.outputs.prop }}
|
||||
files: |
|
||||
${{ env.zipFile }}
|
||||
${{ env.zipFileSHA256 }}
|
||||
package.json
|
17
.github/workflows/build-test-docs.yml
vendored
17
.github/workflows/build-test-docs.yml
vendored
@ -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
58
.github/workflows/changelog-check.yml
vendored
Normal 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
|
5
.github/workflows/deploy-pages.yml
vendored
5
.github/workflows/deploy-pages.yml
vendored
@ -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
|
||||
@ -122,7 +125,7 @@ jobs:
|
||||
workingDirectory: docs-site~
|
||||
|
||||
- name: Purge cache
|
||||
uses: nathanvaughn/actions-cloudflare-purge@0efc272496735521e97d22ba9caa750c2781e257
|
||||
uses: nathanvaughn/actions-cloudflare-purge@784d555fc0fc48946a1e34873a43fc8cf634bcfa
|
||||
continue-on-error: true
|
||||
with:
|
||||
cf_zone: ${{ secrets.CF_ZONE_ID }}
|
||||
|
231
.github/workflows/perform-release.yml
vendored
Normal file
231
.github/workflows/perform-release.yml
vendored
Normal file
@ -0,0 +1,231 @@
|
||||
name: Perform Release
|
||||
|
||||
# Portions of this workflow are based on https://github.com/anatawa12/AvatarOptimizer/blob/master/.github/workflows/release.yml
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
release_kind:
|
||||
type: choice
|
||||
description: The type of release.
|
||||
default: prerelease
|
||||
required: true
|
||||
options:
|
||||
- prerelease
|
||||
- stable
|
||||
- adhoc
|
||||
publish:
|
||||
description: "True to publish release to git, vpm. if false, this creates release asset only"
|
||||
type: boolean
|
||||
required: false
|
||||
version:
|
||||
description: "Version to release"
|
||||
type: string
|
||||
required: false
|
||||
|
||||
env:
|
||||
PKG_NAME: nadena.dev.modular-avatar
|
||||
RELEASE_TYPE: ${{ github.event.inputs.release_kind }}
|
||||
|
||||
concurrency:
|
||||
group: publish
|
||||
cancel-in-progress: true
|
||||
|
||||
permissions: write-all
|
||||
|
||||
jobs:
|
||||
check-gameci:
|
||||
uses: bdunderscore/modular-avatar/.github/workflows/gameci.yml@main
|
||||
permissions:
|
||||
checks: write
|
||||
contents: read
|
||||
secrets: inherit
|
||||
|
||||
check-docs:
|
||||
name: Build documentation (latest release)
|
||||
uses: bdunderscore/modular-avatar/.github/workflows/build-test-docs.yml@main
|
||||
|
||||
create-release:
|
||||
needs: [ check-gameci, check-docs ]
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Dump GitHub context
|
||||
env:
|
||||
GITHUB_CONTEXT: ${{ toJson(github) }}
|
||||
run: echo "$GITHUB_CONTEXT"
|
||||
|
||||
# https://github.com/orgs/community/discussions/13836#discussioncomment-8535364
|
||||
- uses: actions/create-github-app-token@v2
|
||||
id: app-token
|
||||
with:
|
||||
app-id: ${{ vars.RELEASER_APP_ID }}
|
||||
private-key: ${{ secrets.RELEASER_PRIVATE_KEY }}
|
||||
|
||||
- name: Validate prerelease version
|
||||
id: check-version
|
||||
if: ${{ github.event.inputs.release_kind == 'prerelease' && !contains(github.event.inputs.version, '-') }}
|
||||
run:
|
||||
echo "Prerelease version must contain a hyphen"
|
||||
exit 1
|
||||
|
||||
- name: Validate stable version
|
||||
id: check-version-stable
|
||||
if: ${{ github.event.inputs.release_kind == 'stable' && contains(github.event.inputs.version, '-') }}
|
||||
run:
|
||||
echo "Stable version must not contain a hyphen"
|
||||
exit 1
|
||||
|
||||
- name: Validate adhoc
|
||||
id: validate-adhoc
|
||||
if: ${{ github.event.inputs.release_kind == 'adhoc' && github.event.inputs.publish == 'true' }}
|
||||
run:
|
||||
echo "Adhoc release cannot be published"
|
||||
exit 1
|
||||
|
||||
- name: Set Environment Variables
|
||||
run: |
|
||||
echo "zipFile=${{ env.PKG_NAME }}-${{ github.event.inputs.version }}".zip >> $GITHUB_ENV
|
||||
echo "unityPackage=${{ env.PKG_NAME }}-${{ github.event.inputs.version }}.unitypackage" >> $GITHUB_ENV
|
||||
|
||||
echo "VERSION=${{ github.event.inputs.version }}" >> $GITHUB_ENV
|
||||
|
||||
case "$RELEASE_TYPE" in
|
||||
prerelease)
|
||||
echo "PRERELEASE=true" >> $GITHUB_ENV
|
||||
;;
|
||||
stable)
|
||||
echo "PRERELEASE=false" >> $GITHUB_ENV
|
||||
;;
|
||||
adhoc)
|
||||
echo "PRERELEASE=true" >> $GITHUB_ENV
|
||||
;;
|
||||
esac
|
||||
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
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
|
||||
run: |
|
||||
chmod +x .github/workflows/*.sh
|
||||
.github/workflows/check-semver-syntax.sh ${{ github.event.inputs.version }}
|
||||
|
||||
- name: Set git user and email
|
||||
id: git-config
|
||||
run: |
|
||||
git config --global user.name "nadena.dev release bot"
|
||||
git config --global user.email "ci@nadena.dev"
|
||||
- name: Update version
|
||||
id: update-version
|
||||
run: |
|
||||
jq '.version = env.VERSION' package.json > package.json.tmp
|
||||
mv package.json.tmp package.json
|
||||
env:
|
||||
VERSION: ${{ github.event.inputs.version }}
|
||||
|
||||
|
||||
- name: Update changelog
|
||||
id: changelog
|
||||
run: |
|
||||
chmod +x .github/*.pl
|
||||
|
||||
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
|
||||
echo >> release-note.md
|
||||
if [ "${{ env.PRERELEASE }}" == "true" ]; then
|
||||
echo '**This is a prerelease version.** There may be bugs, and API compatibility is not yet guaranteed.' >> release-note.md
|
||||
echo 'Please: **BACK UP YOUR PROJECTS**' >> release-note.md
|
||||
echo >> release-note.md
|
||||
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
|
||||
with:
|
||||
name: CHANGELOG
|
||||
path: CHANGELOG.md
|
||||
- name: Upload CHANGELOG-PRERELEASE.md
|
||||
if: ${{ github.event.inputs.release_kind == 'prerelease' }}
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: CHANGELOG-PRERELEASE
|
||||
path: CHANGELOG-PRERELEASE.md
|
||||
- name: Upload release note
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: changelog
|
||||
path: release-note.md
|
||||
- run: mv release-note.md .github
|
||||
|
||||
- name: Commit and tag version update
|
||||
run: |
|
||||
git commit -am "Release ${{ github.event.inputs.version }}"
|
||||
git tag -a ${{ github.event.inputs.version }} -m "Release ${{ github.event.inputs.version }}"
|
||||
- name: Publish tag
|
||||
if: ${{ github.event.inputs.publish == 'true' }}
|
||||
run: |
|
||||
BRANCH_NAME=$(git branch --show-current)
|
||||
git push origin $BRANCH_NAME && git push origin ${{ github.event.inputs.version }}
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ steps.app-token.outputs.token }}
|
||||
|
||||
- name: Create Zip
|
||||
run: |
|
||||
zip ".github/${{env.zipFile}}" ./* -r -x .github .git '.git/*' '*~/*' '*.ps1*'
|
||||
|
||||
- name: Move zipfile
|
||||
run: |
|
||||
mv .github/${{env.zipFile}} ${{env.zipFile}}
|
||||
|
||||
- uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: package-zip
|
||||
path: ${{ env.zipFile }}
|
||||
|
||||
- name: Dump release notes
|
||||
run: |
|
||||
cat .github/release-note.md
|
||||
|
||||
- name: Make Release
|
||||
uses: softprops/action-gh-release@c95fe1489396fe8a9eb87c0abf8aa5b2ef267fda
|
||||
if: ${{ github.event.inputs.publish == 'true' }}
|
||||
with:
|
||||
draft: true
|
||||
body_path: .github/release-note.md
|
||||
tag_name: ${{ github.event.inputs.version }}
|
||||
name: ${{ github.event.inputs.version }}
|
||||
make_latest: ${{ github.event.inputs.release_kind == 'stable' }}
|
||||
files: |
|
||||
${{ env.zipFile }}
|
||||
package.json
|
129
CHANGELOG-PRERELEASE-jp.md
Normal file
129
CHANGELOG-PRERELEASE-jp.md
Normal file
@ -0,0 +1,129 @@
|
||||
# Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Added
|
||||
|
||||
### Fixed
|
||||
|
||||
### Changed
|
||||
|
||||
### Removed
|
||||
|
||||
### Security
|
||||
|
||||
### 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
|
3
CHANGELOG-PRERELEASE-jp.md.meta
Normal file
3
CHANGELOG-PRERELEASE-jp.md.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2f89fef1421c4126b6086156ff536d8f
|
||||
timeCreated: 1741573199
|
129
CHANGELOG-PRERELEASE.md
Normal file
129
CHANGELOG-PRERELEASE.md
Normal file
@ -0,0 +1,129 @@
|
||||
# Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Added
|
||||
|
||||
### Fixed
|
||||
|
||||
### Changed
|
||||
|
||||
### Removed
|
||||
|
||||
### Security
|
||||
|
||||
### Deprecated
|
||||
|
||||
## [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
|
||||
|
||||
### Changed
|
||||
- [#1476] Switch ModularAvatarMergeAnimator and ModularAvatarMergeParameter to use new NDMF APIs (`IVirtualizeMotion` and `IVirtualizeAnimatorController`)
|
||||
|
||||
## Older versions
|
||||
|
||||
Please see CHANGELOG.md
|
3
CHANGELOG-PRERELEASE.md.meta
Normal file
3
CHANGELOG-PRERELEASE.md.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cb586a9c85634b8b81015d16899d797b
|
||||
timeCreated: 1741571222
|
95
CHANGELOG-jp.md
Normal file
95
CHANGELOG-jp.md
Normal file
@ -0,0 +1,95 @@
|
||||
# Changelog
|
||||
|
||||
Modular Avatarの主な変更点をこのファイルで記録しています。
|
||||
なお、プレリリース版の変更点は `CHANGELOG-PRERELEASE.md` に記録されます。
|
||||
|
||||
この形式は [Keep a Changelog](https://keepachangelog.com/ja/1.0.0/) に基づいており、
|
||||
このプロジェクトは [Semantic Versioning](https://semver.org/lang/ja/) に従っています。
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Added
|
||||
- (実験的機能) VRC以外のプラットフォームのサポートを有効化
|
||||
|
||||
### Fixed
|
||||
|
||||
### Changed
|
||||
|
||||
### Removed
|
||||
|
||||
### Security
|
||||
|
||||
### 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
|
7
CHANGELOG-jp.md.meta
Normal file
7
CHANGELOG-jp.md.meta
Normal file
@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b27815ff13397374abcf9547a36bfaf4
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
100
CHANGELOG.md
100
CHANGELOG.md
@ -1 +1,99 @@
|
||||
Temporary test release
|
||||
# Changelog
|
||||
|
||||
All notable changes to this project will be documented in this file.
|
||||
Changes between prerelease versions will be documented in `CHANGELOG-PRERELEASE.md` instead.
|
||||
|
||||
[日本語版はこちらです。](CHANGELOG-jp.md)
|
||||
|
||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
|
||||
## [Unreleased]
|
||||
|
||||
### Added
|
||||
- (Experimental feature) Enabled support for non-VRC platforms
|
||||
|
||||
### Fixed
|
||||
|
||||
### Changed
|
||||
|
||||
### Removed
|
||||
|
||||
### Security
|
||||
|
||||
### 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
|
||||
|
@ -20,10 +20,26 @@ 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;
|
||||
|
||||
var fx = asc.ControllerContext[VRCAvatarDescriptor.AnimLayerType.FX];
|
||||
// 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;
|
||||
|
||||
var nullMotion = new AnimationClip();
|
||||
|
248
Editor/Animation/MMDRelayPass.cs
Normal file
248
Editor/Animation/MMDRelayPass.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
3
Editor/Animation/MMDRelayPass.cs.meta
Normal file
3
Editor/Animation/MMDRelayPass.cs.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 163fd3d0edea43d5969395079f561986
|
||||
timeCreated: 1741745889
|
@ -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)
|
||||
|
@ -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);
|
||||
|
||||
|
30
Editor/Inspector/MMDModeEditor.cs
Normal file
30
Editor/Inspector/MMDModeEditor.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
3
Editor/Inspector/MMDModeEditor.cs.meta
Normal file
3
Editor/Inspector/MMDModeEditor.cs.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a1a682db3a3b491fa27980adfeeacffd
|
||||
timeCreated: 1741836147
|
@ -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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
var name = forSelection ? selected.name + " Toggle" : "New Toggle";
|
||||
private static ModularAvatarMenuItem CreateSubMenu(GameObject parent, string submenuname)
|
||||
{
|
||||
var submenu = new GameObject(submenuname);
|
||||
submenu.transform.SetParent(parent.transform);
|
||||
|
||||
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();
|
||||
|
@ -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_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();
|
||||
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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();
|
||||
}
|
||||
}, TrickleDown.NoTrickleDown);
|
||||
|
||||
unregisteredListView = root.Q<ListView>("UnregisteredParameters");
|
||||
@ -211,11 +210,6 @@ namespace nadena.dev.modular_avatar.core.editor
|
||||
default: pst = ParameterSyncType.Float; break;
|
||||
}
|
||||
|
||||
if (!parameter.networkSynced)
|
||||
{
|
||||
pst = ParameterSyncType.NotSynced;
|
||||
}
|
||||
|
||||
target.parameters.Add(new ParameterConfig()
|
||||
{
|
||||
internalParameter = false,
|
||||
@ -223,6 +217,7 @@ namespace nadena.dev.modular_avatar.core.editor
|
||||
isPrefix = false,
|
||||
remapTo = "",
|
||||
syncType = pst,
|
||||
localOnly = !parameter.networkSynced,
|
||||
defaultValue = parameter.defaultValue,
|
||||
saved = parameter.saved,
|
||||
});
|
||||
|
@ -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;
|
||||
|
12
Editor/Inspector/WorldScaleObjectEditor.cs
Normal file
12
Editor/Inspector/WorldScaleObjectEditor.cs
Normal 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()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
3
Editor/Inspector/WorldScaleObjectEditor.cs.meta
Normal file
3
Editor/Inspector/WorldScaleObjectEditor.cs.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e9b8b83586074bd7a6441b4cd7539dc9
|
||||
timeCreated: 1741658287
|
3
Editor/Inspector/vrchat.meta
Normal file
3
Editor/Inspector/vrchat.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d59587969bdd48f4ba16883ee3b30d4d
|
||||
timeCreated: 1742695977
|
27
Editor/Inspector/vrchat/VRChatSettingsEditor.cs
Normal file
27
Editor/Inspector/vrchat/VRChatSettingsEditor.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
3
Editor/Inspector/vrchat/VRChatSettingsEditor.cs.meta
Normal file
3
Editor/Inspector/vrchat/VRChatSettingsEditor.cs.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1ffd87033f4d441b849ad147b6e2a6ef
|
||||
timeCreated: 1742695986
|
@ -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"
|
||||
|
||||
}
|
||||
|
@ -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ワールド対応"
|
||||
}
|
||||
|
@ -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": "상대적 경로",
|
||||
|
@ -14,7 +14,7 @@
|
||||
"menuinstall.menu_icon_too_large": "菜单图标过大,图标应小于 256 像素。",
|
||||
"menuinstall.menu_icon_uncompressed": "菜单图标未设置压缩。",
|
||||
"menuinstall.srcmenu": "要安装的菜单",
|
||||
"params.syncmode.NotSynced": "仅 Animator(不同步)",
|
||||
"params.syncmode.NotSynced": "仅 Animator 内部(不同步)",
|
||||
"params.syncmode.Int": "Int",
|
||||
"params.syncmode.Float": "Float",
|
||||
"params.syncmode.Bool": "Bool",
|
||||
@ -65,7 +65,7 @@
|
||||
"merge_armature.mangle_names": "避免名称冲突",
|
||||
"merge_armature.mangle_names.tooltip": "通过重命名新添加的骨骼来避免与其他资源发生名称冲突。",
|
||||
"path_mode.Relative": "相对路径(基于当前对象)",
|
||||
"path_mode.Absolute": "绝对路径(基于 Avatar 的 Root)",
|
||||
"path_mode.Absolute": "绝对路径(基于 Avatar 的根对象)",
|
||||
"merge_animator.animator": "要合并的 Animator",
|
||||
"merge_animator.layer_type": "Layer 类型",
|
||||
"merge_animator.delete_attached_animator": "删除额外的 Animator",
|
||||
@ -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": "相对路径根对象",
|
||||
@ -128,7 +127,7 @@
|
||||
"mesh_settings.inherit_mode.Inherit": "继承",
|
||||
"mesh_settings.inherit_mode.Set": "指定",
|
||||
"mesh_settings.inherit_mode.DontSet": "不指定(保持原有的设置)",
|
||||
"mesh_settings.inherit_mode.SetOrInherit": "父级设置优先,否则遵从指定设置",
|
||||
"mesh_settings.inherit_mode.SetOrInherit": "父级设置优先,否则遵从指定的设置",
|
||||
"pb_blocker.help": "当前对象不会受到附加在父对象的 PhysBones 影响。",
|
||||
"hint.bad_vrcsdk": "检测到不兼容的 VRCSDK 版本。\n\n请尝试升级 VRCSDK;如果这不起作用,请尝试更新到新版本的 Modular Avatar。",
|
||||
"error.stack_trace": "Stack trace(请在报告错误时提供此信息!)",
|
||||
@ -244,7 +243,7 @@
|
||||
"setup_outfit.err.multiple_avatar_descriptors": "在 {0} 和其父级中有多个 Avatar descriptor。\n\n你是要制作「混合 Avatar」吗?如果是,请从「内层 Avatar」中移除 Avatar descriptor 组件,然后对其执行 Setup outfit。",
|
||||
"setup_outfit.err.no_avatar_descriptor": "在 {0} 的父级中找不到 VRC Avatar Descriptor。请确认你的服装是否被正确放置在 Avatar 里。",
|
||||
"setup_outfit.err.no_animator": "你的 Avatar 没有 Animator 组件。",
|
||||
"setup_outfit.err.no_hips": "你的 Avatar 没有 Hips 骨骼。Setup Outfit 只能用于人形(humanoid) 的 Avatar。",
|
||||
"setup_outfit.err.no_hips": "你的 Avatar 没有 Hips 骨骼。Setup Outfit 只能用于人形 (humanoid) 的 Avatar。",
|
||||
"setup_outfit.err.no_outfit_hips": "无法识别服装的 Hips 骨骼,已尝试搜索包含以下名称的对象:",
|
||||
"move_independently.group-header": "要一起移动的对象",
|
||||
"scale_adjuster.scale": "调整比例",
|
||||
|
@ -51,6 +51,7 @@
|
||||
"merge_parameter.ui.add_button": "添加",
|
||||
"merge_parameter.ui.details": "參數設定",
|
||||
"merge_parameter.ui.overrideAnimatorDefaults": "覆蓋 Animator 預設值",
|
||||
"merge_parameter.ui.importFromAsset": "從 Assets 匯入",
|
||||
"merge_armature.merge_target": "合併目標",
|
||||
"merge_armature.merge_target.tooltip": "當前物件要合併到的骨架(或其子級)",
|
||||
"merge_armature.prefix": "骨骼前綴",
|
||||
@ -86,12 +87,12 @@
|
||||
"merge_armature.lockmode.bidirectional.body": "Avatar 骨骼和當前物件的骨骼的位置始終相同。\n此模式對創建基於 Avatar 骨骼的動畫時非常有用。\n啟用此模式要求 Avatar 骨骼和當前物件的骨骼位置完全相同。",
|
||||
"merge_armature.reset_pos": "將位置與 Avatar 進行對齊",
|
||||
"merge_armature.reset_pos.info": "此命令將強制服裝骨骼與 Avatar 骨骼進行對齊,在使用非 Avatar 對應的服裝時可能有幫助。",
|
||||
"merge_armature.reset_pos.convert_atpose": "轉換 A-Pose/T-Pose 以符合角色",
|
||||
"merge_armature.reset_pos.adjust_rotation": "也對齊旋轉",
|
||||
"merge_armature.reset_pos.adjust_scale": "也對齊縮放",
|
||||
"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": "相對路徑根物件",
|
||||
@ -99,6 +100,7 @@
|
||||
"worldfixed.quest": "此元件未生效,因為它與 Android 環境不相容。",
|
||||
"worldfixed.normal": "當前物件將會固定於世界,除非你使用約束將它綁在 Avatar 內。",
|
||||
"fpvisible.normal": "當前物件將在第一人稱視角中可見。",
|
||||
"fpvisible.NotUnderHead": "此元件在未放置於 Head 骨骼下時不會生效。\n如果是透過 Bone Proxy 等方式將其放於 Head 骨骼下,則可忽略此警告。",
|
||||
"fpvisible.quest": "此元件未生效,因為它與 Android 環境不相容。",
|
||||
"fpvisible.InPhysBoneChain": "當前物件由 Physics Bone 控制,可能無法在第一人稱視角中可見;請指定 Physics Bone 鏈的起點。",
|
||||
"blendshape.mesh": "網格",
|
||||
@ -148,6 +150,9 @@
|
||||
"error.rename_params.default_value_conflict:hint": "為了避免不可預測的行為,請將 MA Parameters 元件中所有預設值留空,只留一個。如果存在多個值,Modular Avatar 將選擇第一個預設值。",
|
||||
"error.replace_object.null_target": "[MA-0008] 未指定要替換的物件",
|
||||
"error.replace_object.null_target:hint": "Replace object 需要知道要替換掉哪個物件。嘗試指定一個。",
|
||||
"error.replace_object.replacing_replacement": "[MA-0009] 不能在多個 Replace Object 元件中指定相同的目標物件",
|
||||
"error.replace_object.parent_of_target": "[MA-0010] 目標物件不能是此物件的父級",
|
||||
"error.singleton": "[MA-0011] 在一個 Avatar 中只允許存在單個 {0} 元件",
|
||||
"validation.blendshape_sync.no_local_renderer": "[MA-1000] 在此物件上找不到 Renderer",
|
||||
"validation.blendshape_sync.no_local_renderer:hint": "Blendshape Sync 作用於所在物件上的 Skinned Mesh Renderer。你是否將它附加到正確的物件上?",
|
||||
"validation.blendshape_sync.no_local_mesh": "[MA-1001] 在此物件的 Renderer 上找不到網格(Mesh)",
|
||||
@ -187,6 +192,7 @@
|
||||
"menuitem.prop.value": "參數值",
|
||||
"menuitem.prop.value.tooltip": "設定選單項觸發時的參數值",
|
||||
"menuitem.prop.automatic_value": "自動",
|
||||
"menuitem.prop.automatic_value.tooltip": "自動將此控制設定為唯一值",
|
||||
"menuitem.prop.parameter": "參數",
|
||||
"menuitem.prop.label": "名稱",
|
||||
"menuitem.prop.submenu_asset": "子選單資源",
|
||||
@ -238,6 +244,7 @@
|
||||
"setup_outfit.err.no_avatar_descriptor": "在 {0} 的父級中找不到 VRC Avatar Descriptor。請確保你的服裝放置在 Avatar 裡。",
|
||||
"setup_outfit.err.no_animator": "你的 Avatar 沒有 Animator 元件。",
|
||||
"setup_outfit.err.no_hips": "你的 Avatar 沒有 Hips 骨骼。Setup Outfit 只能用於 humanoid Avatars。",
|
||||
"setup_outfit.err.no_outfit_hips": "識別不到服裝的 Hips 骨骼,已嘗試搜尋含有以下名稱的骨骼物件(不區分大小寫):",
|
||||
"move_independently.group-header": "要一起移動的物件",
|
||||
"scale_adjuster.scale": "調整比例",
|
||||
"scale_adjuster.adjust_children": "調整子級的位置",
|
||||
@ -272,5 +279,17 @@
|
||||
"ro_sim.effect_group.material.tooltip": "Reactive Component 啟用時,將被設在目標元件上的材質",
|
||||
"ro_sim.effect_group.rule_inverted": "規則的條件已反轉",
|
||||
"ro_sim.effect_group.rule_inverted.tooltip": "這條規則將在未達成其任一條件時套用。",
|
||||
"ro_sim.effect_group.conditions": "條件"
|
||||
"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": "保留頂點顏色",
|
||||
"general.vrcsdk-required": "此元件需要 VRCSDK 才能運作。",
|
||||
"sync-param-sequence.platform": "主平台",
|
||||
"sync-param-sequence.platform.tooltip": "此平台進行建置時,Modular Avatar 將記錄所有參數,供其他平台使用。",
|
||||
"sync-param-sequence.parameters": "共用的參數資源",
|
||||
"sync-param-sequence.parameters.tooltip": "用來儲存共用參數的資源檔。請勿使用已在 Avatar Descriptor 中設定的相同參數。",
|
||||
"sync-param-sequence.create-asset": "新增",
|
||||
"sync-param-sequence.create-asset.tooltip": "創建一個新的 Expression Parameters"
|
||||
}
|
||||
|
@ -24,9 +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;
|
||||
@ -37,6 +41,23 @@ namespace nadena.dev.modular_avatar.core.editor
|
||||
{
|
||||
private AnimatorServicesContext _asc;
|
||||
|
||||
[InitializeOnLoadMethod]
|
||||
private static void Init()
|
||||
{
|
||||
ModularAvatarMergeAnimator.GetMotionBasePathCallback = (merge, objectBuildContext) =>
|
||||
{
|
||||
if (merge.pathMode == MergeAnimatorPathMode.Absolute) return "";
|
||||
|
||||
var context = (ndmf.BuildContext)objectBuildContext;
|
||||
|
||||
var targetObject = merge.relativePathRoot.Get(context.AvatarRootTransform);
|
||||
if (targetObject == null) targetObject = merge.gameObject;
|
||||
|
||||
var relativePath = RuntimeUtil.RelativePath(context.AvatarRootObject, targetObject);
|
||||
return relativePath != "" ? relativePath : "";
|
||||
};
|
||||
}
|
||||
|
||||
internal void OnPreprocessAvatar(GameObject avatarGameObject, BuildContext context)
|
||||
{
|
||||
_asc = context.PluginBuildContext.Extension<AnimatorServicesContext>();
|
||||
@ -68,23 +89,32 @@ 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[layerType];
|
||||
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());
|
||||
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);
|
||||
|
||||
bool? writeDefaults = null;
|
||||
if (wdStateCounter.Count == 1) writeDefaults = wdStateCounter.First().Key;
|
||||
// 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)
|
||||
{
|
||||
@ -92,50 +122,67 @@ namespace nadena.dev.modular_avatar.core.editor
|
||||
}
|
||||
}
|
||||
|
||||
private void MergeSingle(BuildContext context, VirtualAnimatorController controller, ModularAvatarMergeAnimator merge, bool? initialWriteDefaults)
|
||||
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)
|
||||
{
|
||||
if (merge.animator == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var stash = context.PluginBuildContext.GetState<RenamedMergeAnimators>();
|
||||
|
||||
var clonedController = stash.Controllers.GetValueOrDefault(merge)
|
||||
?? _asc.ControllerContext.CloneContext.CloneDistinct(merge.animator);
|
||||
|
||||
string basePath;
|
||||
if (merge.pathMode == MergeAnimatorPathMode.Relative)
|
||||
if (!merge.matchAvatarWriteDefaults)
|
||||
{
|
||||
var targetObject = merge.relativePathRoot.Get(context.AvatarRootTransform);
|
||||
if (targetObject == null) targetObject = merge.gameObject;
|
||||
|
||||
var relativePath = RuntimeUtil.RelativePath(context.AvatarRootObject, targetObject);
|
||||
basePath = relativePath != "" ? relativePath + "/" : "";
|
||||
|
||||
var animationIndex = new AnimationIndex(new[] { clonedController });
|
||||
animationIndex.RewritePaths(p => p == "" ? relativePath : basePath + p);
|
||||
}
|
||||
else
|
||||
{
|
||||
basePath = "";
|
||||
initialWriteDefaults = null;
|
||||
}
|
||||
|
||||
var vac = context.PluginBuildContext.Extension<VirtualControllerContext>();
|
||||
|
||||
if (!vac.Controllers.TryGetValue(merge, out var clonedController)) return;
|
||||
|
||||
var firstLayer = clonedController.Layers.FirstOrDefault();
|
||||
// the first layer in an animator controller always has weight 1.0f (regardless of what is serialized)
|
||||
if (firstLayer != null) firstLayer.DefaultWeight = 1.0f;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
controller.AddLayer(new LayerPriority(merge.layerPriority), l);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
foreach (var (name, parameter) in clonedController.Parameters)
|
||||
{
|
||||
if (controller.Parameters.TryGetValue(name, out var existingParam))
|
||||
if (targetController.Parameters.TryGetValue(name, out var existingParam))
|
||||
{
|
||||
if (existingParam.type != parameter.type)
|
||||
{
|
||||
@ -152,12 +199,12 @@ namespace nadena.dev.modular_avatar.core.editor
|
||||
|
||||
existingParam.type = AnimatorControllerParameterType.Float;
|
||||
|
||||
controller.Parameters = controller.Parameters.SetItem(name, existingParam);
|
||||
targetController.Parameters = targetController.Parameters.SetItem(name, existingParam);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
controller.Parameters = controller.Parameters.Add(name, parameter);
|
||||
targetController.Parameters = targetController.Parameters.Add(name, parameter);
|
||||
}
|
||||
|
||||
if (merge.deleteAttachedAnimator)
|
||||
@ -165,6 +212,18 @@ namespace nadena.dev.modular_avatar.core.editor
|
||||
var animator = merge.GetComponent<Animator>();
|
||||
if (animator != null) Object.DestroyImmediate(animator);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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>();
|
||||
@ -178,7 +178,7 @@ namespace nadena.dev.modular_avatar.core.editor
|
||||
return cached;
|
||||
}
|
||||
|
||||
var obj = asc.ObjectPathRemapper.GetObjectForPath(bindingPath)!.transform;
|
||||
var obj = asc.ObjectPathRemapper.GetObjectForPath(bindingPath)?.transform;
|
||||
while (obj != null && transformLookthrough.Contains(obj))
|
||||
{
|
||||
obj = obj.parent;
|
||||
@ -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,7 +377,6 @@ namespace nadena.dev.modular_avatar.core.editor
|
||||
|
||||
if (zipMerge)
|
||||
{
|
||||
mergedObjects.Add(src.transform);
|
||||
thisPassAdded.Add(src.transform);
|
||||
}
|
||||
|
||||
@ -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,21 +484,32 @@ 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RecursiveMerge(config, childGameObject, childNewParent, shouldZip);
|
||||
@ -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);
|
||||
|
@ -2,17 +2,21 @@
|
||||
|
||||
#region
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using nadena.dev.ndmf;
|
||||
using nadena.dev.ndmf.animator;
|
||||
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";
|
||||
@ -22,13 +26,28 @@ namespace nadena.dev.modular_avatar.core.editor
|
||||
private VirtualBlendTree _rootBlendTree;
|
||||
private HashSet<string> _parameterNames;
|
||||
|
||||
[InitializeOnLoadMethod]
|
||||
private static void Init()
|
||||
{
|
||||
ModularAvatarMergeBlendTree.GetMotionBasePathCallback = (mbt, objectBuildContext) =>
|
||||
{
|
||||
if (mbt.PathMode == MergeAnimatorPathMode.Absolute) return "";
|
||||
|
||||
var buildContext = (ndmf.BuildContext)objectBuildContext;
|
||||
var root = mbt.RelativePathRoot.Get(buildContext.AvatarRootTransform);
|
||||
if (root == null) root = mbt.gameObject;
|
||||
|
||||
return RuntimeUtil.AvatarRootPath(root);
|
||||
};
|
||||
}
|
||||
|
||||
protected override void Execute(ndmf.BuildContext context)
|
||||
{
|
||||
_asc = context.Extension<AnimatorServicesContext>();
|
||||
_rootBlendTree = null;
|
||||
_parameterNames = new HashSet<string>();
|
||||
|
||||
var fx = _asc.ControllerContext[VRCAvatarDescriptor.AnimLayerType.FX];
|
||||
var fx = _asc.ControllerContext.Controllers[VRCAvatarDescriptor.AnimLayerType.FX];
|
||||
|
||||
foreach (var component in
|
||||
context.AvatarRootObject.GetComponentsInChildren<ModularAvatarMergeBlendTree>(true))
|
||||
@ -46,61 +65,56 @@ namespace nadena.dev.modular_avatar.core.editor
|
||||
|
||||
foreach (var name in _parameterNames)
|
||||
{
|
||||
if (fx.Parameters.ContainsKey(name)) continue;
|
||||
if (fx.Parameters.TryGetValue(name, out var existingParameter))
|
||||
{
|
||||
switch (existingParameter.type)
|
||||
{
|
||||
case AnimatorControllerParameterType.Bool:
|
||||
existingParameter.defaultFloat = existingParameter.defaultBool ? 1 : 0;
|
||||
break;
|
||||
case AnimatorControllerParameterType.Int:
|
||||
existingParameter.defaultFloat = existingParameter.defaultInt;
|
||||
break;
|
||||
}
|
||||
|
||||
fx.Parameters = fx.Parameters.SetItem(name, new AnimatorControllerParameter()
|
||||
existingParameter.type = AnimatorControllerParameterType.Float;
|
||||
}
|
||||
else
|
||||
{
|
||||
existingParameter = new AnimatorControllerParameter
|
||||
{
|
||||
name = name,
|
||||
type = AnimatorControllerParameterType.Float,
|
||||
defaultFloat = 0.0f
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
fx.Parameters = fx.Parameters.SetItem(name, existingParameter);
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessComponent(BuildContext context, ModularAvatarMergeBlendTree component)
|
||||
{
|
||||
var stash = context.PluginBuildContext.GetState<RenamedMergeAnimators>();
|
||||
var virtualBlendTree = _asc.ControllerContext.GetVirtualizedMotion(component);
|
||||
|
||||
BlendTree componentBlendTree = component.BlendTree as BlendTree;
|
||||
|
||||
if (componentBlendTree == null)
|
||||
if (virtualBlendTree == null)
|
||||
{
|
||||
ErrorReport.ReportError(Localization.L, ErrorSeverity.NonFatal, "error.merge_blend_tree.missing_tree");
|
||||
return;
|
||||
}
|
||||
|
||||
string basePath = null;
|
||||
string rootPath = null;
|
||||
if (component.PathMode == MergeAnimatorPathMode.Relative)
|
||||
{
|
||||
var root = component.RelativePathRoot.Get(context.AvatarRootTransform);
|
||||
if (root == null) root = component.gameObject;
|
||||
|
||||
rootPath = RuntimeUtil.AvatarRootPath(root);
|
||||
basePath = rootPath + "/";
|
||||
}
|
||||
|
||||
var bt = stash.BlendTrees.GetValueOrDefault(component)
|
||||
?? _asc.ControllerContext.CloneContext.Clone(componentBlendTree);
|
||||
|
||||
if (basePath != null)
|
||||
{
|
||||
var animationIndex = new AnimationIndex(new[] { bt });
|
||||
animationIndex.RewritePaths(p => p == "" ? rootPath : basePath + p);
|
||||
}
|
||||
|
||||
var rootBlend = GetRootBlendTree();
|
||||
|
||||
rootBlend.Children = rootBlend.Children.Add(new()
|
||||
{
|
||||
Motion = bt,
|
||||
Motion = virtualBlendTree,
|
||||
DirectBlendParameter = ALWAYS_ONE,
|
||||
Threshold = 1,
|
||||
CycleOffset = 1,
|
||||
TimeScale = 1,
|
||||
});
|
||||
|
||||
foreach (var asset in bt.AllReachableNodes())
|
||||
foreach (var asset in virtualBlendTree.AllReachableNodes())
|
||||
{
|
||||
if (asset is VirtualBlendTree bt2)
|
||||
{
|
||||
@ -129,15 +143,21 @@ namespace nadena.dev.modular_avatar.core.editor
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Object.DestroyImmediate(component);
|
||||
}
|
||||
|
||||
private VirtualBlendTree GetRootBlendTree()
|
||||
{
|
||||
if (_rootBlendTree != null) return _rootBlendTree;
|
||||
|
||||
var fx = _asc.ControllerContext[VRCAvatarDescriptor.AnimLayerType.FX];
|
||||
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);
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -37,6 +37,7 @@ namespace nadena.dev.modular_avatar.core.editor
|
||||
public static ImmutableHashSet<string> VRCSDKParameters = new string[]
|
||||
{
|
||||
"IsLocal",
|
||||
"PreviewMode",
|
||||
"Viseme",
|
||||
"Voice",
|
||||
"GestureLeft",
|
||||
@ -155,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;
|
||||
}
|
||||
|
||||
|
@ -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,37 +86,44 @@ 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.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);
|
||||
#endif
|
||||
|
||||
seq.Run(ConstraintConverterPass.Instance);
|
||||
#endif
|
||||
|
||||
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.OnPlatforms(new[] { WellKnownPlatforms.VRChatAvatar30 }, _seq =>
|
||||
{
|
||||
seq.Run("Fixup Expressions Menu", ctx =>
|
||||
{
|
||||
var maContext = ctx.Extension<ModularAvatarContext>().BuildContext;
|
||||
FixupExpressionsMenuPass.FixupExpressionsMenu(maContext);
|
||||
});
|
||||
});
|
||||
seq.Run(SyncParameterSequencePass.Instance);
|
||||
#endif
|
||||
seq.Run(RemoveVertexColorPass.Instance).PreviewingWith(new RemoveVertexColorPreview());
|
||||
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -255,7 +255,7 @@ namespace nadena.dev.modular_avatar.core.editor
|
||||
var action = ObjectRule(key, changer, value);
|
||||
action.Inverted = _computeContext.Observe(changer, c => c.Inverted);
|
||||
|
||||
if (changer.gameObject.activeInHierarchy) info.currentState = action.Value;
|
||||
info.currentState = currentValue;
|
||||
|
||||
if (info.actionGroups.Count == 0)
|
||||
{
|
||||
|
@ -1,4 +1,5 @@
|
||||
#if MA_VRCSDK3_AVATARS
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
@ -21,6 +22,9 @@ namespace nadena.dev.modular_avatar.core.editor
|
||||
private readonly AnimatorServicesContext _asc;
|
||||
private readonly ReadablePropertyExtension _rpe;
|
||||
|
||||
private static readonly ImmutableHashSet<Type> ActiveObjectTypes =
|
||||
new[] { typeof(AudioSource) }.ToImmutableHashSet();
|
||||
|
||||
private Dictionary<string, float> _simulationInitialStates;
|
||||
|
||||
public const string BlendshapePrefix = "blendShape.";
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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[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);
|
||||
@ -593,9 +604,7 @@ namespace nadena.dev.modular_avatar.core.editor
|
||||
private void ApplyController(AnimatorStateMachine asm, string layerName)
|
||||
{
|
||||
var asc = context.Extension<AnimatorServicesContext>();
|
||||
var fx = asc.ControllerContext[
|
||||
VRCAvatarDescriptor.AnimLayerType.FX
|
||||
];
|
||||
var fx = asc.ControllerContext.Controllers[VRCAvatarDescriptor.AnimLayerType.FX];
|
||||
|
||||
if (fx == null)
|
||||
{
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,6 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using nadena.dev.ndmf;
|
||||
using nadena.dev.ndmf.animator;
|
||||
using UnityEditor.Animations;
|
||||
using UnityEngine;
|
||||
using VRC.SDK3.Avatars.Components;
|
||||
using VRC.SDK3.Avatars.ScriptableObjects;
|
||||
@ -55,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())
|
||||
@ -73,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}")
|
||||
};
|
||||
}
|
||||
|
||||
@ -203,7 +204,7 @@ namespace nadena.dev.modular_avatar.core.editor
|
||||
if (mamiWithRC.Count > 0)
|
||||
{
|
||||
var asc = context.Extension<AnimatorServicesContext>();
|
||||
var fx = asc.ControllerContext[VRCAvatarDescriptor.AnimLayerType.FX];
|
||||
var fx = asc.ControllerContext.Controllers[VRCAvatarDescriptor.AnimLayerType.FX];
|
||||
|
||||
foreach (var (name, _) in mamiWithRC)
|
||||
{
|
||||
|
@ -1,4 +1,4 @@
|
||||
#if MA_VRCSDK3_AVATARS
|
||||
#if MA_VRCSDK3_AVATARS
|
||||
|
||||
#region
|
||||
|
||||
@ -6,11 +6,12 @@ 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;
|
||||
using UnityEditor;
|
||||
using UnityEditor.Animations;
|
||||
using UnityEngine;
|
||||
using VRC.SDK3.Avatars.Components;
|
||||
using VRC.SDK3.Avatars.ScriptableObjects;
|
||||
@ -18,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
|
||||
@ -31,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;
|
||||
@ -55,43 +75,6 @@ namespace nadena.dev.modular_avatar.core.editor
|
||||
public ImmutableDictionary<string, float> InitialValueOverrides;
|
||||
}
|
||||
|
||||
internal class RenamedMergeAnimators
|
||||
{
|
||||
public AnimatorServicesContext AnimatorServices;
|
||||
public Dictionary<ModularAvatarMergeAnimator, VirtualAnimatorController> Controllers = new();
|
||||
public Dictionary<ModularAvatarMergeBlendTree, VirtualBlendTree> BlendTrees = new();
|
||||
|
||||
public VirtualAnimatorController Clone(ModularAvatarMergeAnimator mama)
|
||||
{
|
||||
if (Controllers.TryGetValue(mama, out var controller))
|
||||
{
|
||||
return controller;
|
||||
}
|
||||
|
||||
if (mama.animator == null) return null;
|
||||
|
||||
var cloned = AnimatorServices.ControllerContext.CloneContext.CloneDistinct(mama.animator, mama.layerType);
|
||||
Controllers[mama] = cloned;
|
||||
|
||||
return cloned;
|
||||
}
|
||||
|
||||
public VirtualBlendTree Clone(ModularAvatarMergeBlendTree mbt)
|
||||
{
|
||||
if (BlendTrees.TryGetValue(mbt, out var blendTree))
|
||||
{
|
||||
return blendTree;
|
||||
}
|
||||
|
||||
if (mbt.BlendTree is not BlendTree bt) return null;
|
||||
|
||||
var cloned = (VirtualBlendTree)AnimatorServices.ControllerContext.CloneContext.Clone(bt);
|
||||
BlendTrees[mbt] = cloned;
|
||||
|
||||
return cloned;
|
||||
}
|
||||
}
|
||||
|
||||
internal class RenameParametersHook
|
||||
{
|
||||
private const string DEFAULT_EXP_PARAMS_ASSET_GUID = "03a6d797deb62f0429471c4e17ea99a7";
|
||||
@ -111,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;
|
||||
|
||||
@ -200,10 +183,6 @@ namespace nadena.dev.modular_avatar.core.editor
|
||||
|
||||
_context = context;
|
||||
|
||||
var stash = _context.PluginBuildContext.GetState<RenamedMergeAnimators>();
|
||||
var asc = _context.PluginBuildContext.Extension<AnimatorServicesContext>();
|
||||
stash.AnimatorServices = asc;
|
||||
|
||||
var syncParams = WalkTree(avatar);
|
||||
|
||||
SetExpressionParameters(avatar, syncParams);
|
||||
@ -216,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)
|
||||
@ -359,6 +338,8 @@ namespace nadena.dev.modular_avatar.core.editor
|
||||
GameObject obj
|
||||
)
|
||||
{
|
||||
var animServices = _context.PluginBuildContext.Extension<AnimatorServicesContext>();
|
||||
|
||||
var paramInfo = ndmf.ParameterInfo.ForContext(_context.PluginBuildContext);
|
||||
|
||||
ImmutableDictionary<string, ParameterInfo> rv = ImmutableDictionary<string, ParameterInfo>.Empty;
|
||||
@ -406,7 +387,7 @@ namespace nadena.dev.modular_avatar.core.editor
|
||||
break;
|
||||
}
|
||||
|
||||
case ModularAvatarMergeAnimator merger:
|
||||
case IVirtualizeAnimatorController or IVirtualizeMotion:
|
||||
{
|
||||
var mappings = paramInfo.GetParameterRemappingsAt(obj);
|
||||
var remap = mappings.SelectMany(item =>
|
||||
@ -421,31 +402,10 @@ namespace nadena.dev.modular_avatar.core.editor
|
||||
);
|
||||
}).ToImmutableDictionary();
|
||||
|
||||
if (merger.animator != null)
|
||||
var controller = animServices.ControllerContext.Controllers[component];
|
||||
if (controller != null)
|
||||
{
|
||||
var stash = _context.PluginBuildContext.GetState<RenamedMergeAnimators>();
|
||||
|
||||
var controller = stash.Clone(merger);
|
||||
|
||||
ProcessVirtualAnimatorController(controller, remap);
|
||||
|
||||
stash.Controllers[merger] = controller;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case ModularAvatarMergeBlendTree merger:
|
||||
{
|
||||
var bt = merger.BlendTree as BlendTree;
|
||||
if (bt != null)
|
||||
{
|
||||
var stash = _context.PluginBuildContext.GetState<RenamedMergeAnimators>();
|
||||
|
||||
var virtualbt = stash.Clone(merger);
|
||||
ProcessBlendtree(virtualbt, paramInfo.GetParameterRemappingsAt(obj));
|
||||
|
||||
stash.BlendTrees[merger] = virtualbt;
|
||||
}
|
||||
|
||||
break;
|
||||
@ -564,7 +524,7 @@ namespace nadena.dev.modular_avatar.core.editor
|
||||
{
|
||||
case VirtualStateMachine vsm: ProcessStateMachine(vsm, remap); break;
|
||||
case VirtualState vs: ProcessState(vs, remap); break;
|
||||
case VirtualTransition vt: ProcessTransition(vt, remap); break;
|
||||
case VirtualTransitionBase vt: ProcessTransition(vt, remap); break;
|
||||
case VirtualClip vc: ProcessClip(vc, remap); break;
|
||||
case VirtualBlendTree bt: ProcessBlendtree(bt, remap); break;
|
||||
}
|
||||
|
@ -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
3
Editor/VRChat.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 476a3ae35e5046989e0c7276ae860e3c
|
||||
timeCreated: 1742695540
|
24
Editor/VRChat/VRChatSettingsPass.cs
Normal file
24
Editor/VRChat/VRChatSettingsPass.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
3
Editor/VRChat/VRChatSettingsPass.cs.meta
Normal file
3
Editor/VRChat/VRChatSettingsPass.cs.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cc7a69c0f9aa469dbcf8d4b492f5a6d9
|
||||
timeCreated: 1742695552
|
@ -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
|
||||
}
|
||||
}
|
47
Editor/WorldScaleObjectPass.cs
Normal file
47
Editor/WorldScaleObjectPass.cs
Normal 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);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
3
Editor/WorldScaleObjectPass.cs.meta
Normal file
3
Editor/WorldScaleObjectPass.cs.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 19a3b07a9eeb413887792469f344c34d
|
||||
timeCreated: 1741657804
|
@ -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": [],
|
||||
|
@ -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
|
||||
}
|
@ -23,9 +23,9 @@
|
||||
*/
|
||||
|
||||
using System;
|
||||
using nadena.dev.ndmf;
|
||||
using UnityEngine;
|
||||
#if MA_VRCSDK3_AVATARS
|
||||
using VRC.SDKBase;
|
||||
#endif
|
||||
|
||||
namespace nadena.dev.modular_avatar.core
|
||||
@ -35,7 +35,7 @@ namespace nadena.dev.modular_avatar.core
|
||||
/// inherited by user classes, and will be removed in Modular Avatar 2.0.
|
||||
/// </summary>
|
||||
[DefaultExecutionOrder(-9999)] // run before av3emu
|
||||
public abstract class AvatarTagComponent : MonoBehaviour, IEditorOnly
|
||||
public abstract class AvatarTagComponent : MonoBehaviour, INDMFEditorOnly
|
||||
{
|
||||
internal static event Action OnChangeAction;
|
||||
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 547 B After Width: | Height: | Size: 3.5 KiB |
@ -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;
|
||||
|
||||
|
23
Runtime/ModularAvatarMMDLayerControl.cs
Normal file
23
Runtime/ModularAvatarMMDLayerControl.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
3
Runtime/ModularAvatarMMDLayerControl.cs.meta
Normal file
3
Runtime/ModularAvatarMMDLayerControl.cs.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d1d979d3cedd4ddd969f414e2ea04fb8
|
||||
timeCreated: 1741836107
|
@ -25,6 +25,7 @@
|
||||
#if MA_VRCSDK3_AVATARS
|
||||
|
||||
using System;
|
||||
using nadena.dev.ndmf.animator;
|
||||
using UnityEngine;
|
||||
using VRC.SDK3.Avatars.Components;
|
||||
|
||||
@ -36,10 +37,19 @@ 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
|
||||
public class ModularAvatarMergeAnimator : AvatarTagComponent, IVirtualizeAnimatorController
|
||||
{
|
||||
internal static Func<ModularAvatarMergeAnimator, object, string> GetMotionBasePathCallback =
|
||||
(_, _) => "";
|
||||
|
||||
public RuntimeAnimatorController animator;
|
||||
public VRCAvatarDescriptor.AnimLayerType layerType = VRCAvatarDescriptor.AnimLayerType.FX;
|
||||
public bool deleteAttachedAnimator;
|
||||
@ -47,6 +57,7 @@ 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()
|
||||
{
|
||||
@ -67,6 +78,22 @@ namespace nadena.dev.modular_avatar.core
|
||||
{
|
||||
deleteAttachedAnimator = true;
|
||||
}
|
||||
|
||||
RuntimeAnimatorController IVirtualizeAnimatorController.AnimatorController
|
||||
{
|
||||
get => animator;
|
||||
set => animator = value;
|
||||
}
|
||||
|
||||
string IVirtualizeAnimatorController.GetMotionBasePath(object ndmfBuildContext, bool clearPath)
|
||||
{
|
||||
var path = GetMotionBasePathCallback(this, ndmfBuildContext);
|
||||
if (clearPath) pathMode = MergeAnimatorPathMode.Absolute;
|
||||
|
||||
return path;
|
||||
}
|
||||
|
||||
object IVirtualizeAnimatorController.TargetControllerKey => layerType;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,17 +1,61 @@
|
||||
#if MA_VRCSDK3_AVATARS
|
||||
|
||||
using System;
|
||||
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
|
||||
public sealed class ModularAvatarMergeBlendTree : AvatarTagComponent, IVirtualizeMotion
|
||||
{
|
||||
// We can't actually reference a BlendTree here because it's not available when building a player build
|
||||
public UnityEngine.Object BlendTree;
|
||||
internal static Func<ModularAvatarMergeBlendTree, object, string> GetMotionBasePathCallback
|
||||
= (_, _) => "";
|
||||
|
||||
// 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)
|
||||
{
|
||||
var path = GetMotionBasePathCallback(this, ndmfBuildContext);
|
||||
|
||||
if (clearPath)
|
||||
{
|
||||
PathMode = MergeAnimatorPathMode.Absolute;
|
||||
}
|
||||
|
||||
return path;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
20
Runtime/ModularAvatarVRChatSettings.cs
Normal file
20
Runtime/ModularAvatarVRChatSettings.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
11
Runtime/ModularAvatarVRChatSettings.cs.meta
Normal file
11
Runtime/ModularAvatarVRChatSettings.cs.meta
Normal 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:
|
12
Runtime/ModularAvatarWorldScaleObject.cs
Normal file
12
Runtime/ModularAvatarWorldScaleObject.cs
Normal 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
|
||||
}
|
||||
}
|
11
Runtime/ModularAvatarWorldScaleObject.cs.meta
Normal file
11
Runtime/ModularAvatarWorldScaleObject.cs.meta
Normal 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:
|
@ -31,7 +31,7 @@ public class ActiveAnimationRetargeterTests : TestBase
|
||||
var created = retargeter.CreateIntermediateObjects(newParent.gameObject);
|
||||
retargeter.FixupAnimations();
|
||||
|
||||
var fx = asc.ControllerContext[VRCAvatarDescriptor.AnimLayerType.FX]!;
|
||||
var fx = asc.ControllerContext.Controllers[VRCAvatarDescriptor.AnimLayerType.FX]!;
|
||||
var clip = (VirtualClip) fx.Layers.First(l => l.Name == "retarget").StateMachine.DefaultState!.Motion;
|
||||
var curveBindings = clip!.GetFloatCurveBindings();
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
3
UnitTests~/Animation/MMD.meta
Normal file
3
UnitTests~/Animation/MMD.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 046888971cba42e895a515d3d07b955b
|
||||
timeCreated: 1742001943
|
192
UnitTests~/Animation/MMD/AC1.controller
Normal file
192
UnitTests~/Animation/MMD/AC1.controller
Normal 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}
|
8
UnitTests~/Animation/MMD/AC1.controller.meta
Normal file
8
UnitTests~/Animation/MMD/AC1.controller.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e7f6321e9d2601a45a3efa0a24305b78
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 9100000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
192
UnitTests~/Animation/MMD/AC2.controller
Normal file
192
UnitTests~/Animation/MMD/AC2.controller
Normal 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}
|
8
UnitTests~/Animation/MMD/AC2.controller.meta
Normal file
8
UnitTests~/Animation/MMD/AC2.controller.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bf8dbf58ea7a7544cb5c7f86b790d0ff
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 9100000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
138
UnitTests~/Animation/MMD/MMDHandlingTests.cs
Normal file
138
UnitTests~/Animation/MMD/MMDHandlingTests.cs
Normal 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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
3
UnitTests~/Animation/MMD/MMDHandlingTests.cs.meta
Normal file
3
UnitTests~/Animation/MMD/MMDHandlingTests.cs.meta
Normal file
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 298d11b5361148b499d196aabcaaab73
|
||||
timeCreated: 1742002556
|
380
UnitTests~/Animation/MMD/MMDMode_MergeBefore.prefab
Normal file
380
UnitTests~/Animation/MMD/MMDMode_MergeBefore.prefab
Normal 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
|
7
UnitTests~/Animation/MMD/MMDMode_MergeBefore.prefab.meta
Normal file
7
UnitTests~/Animation/MMD/MMDMode_MergeBefore.prefab.meta
Normal file
@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5cd01837b01aa8b4897906d81b421b32
|
||||
PrefabImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
325
UnitTests~/Animation/MMD/MMDMode_Noop.prefab
Normal file
325
UnitTests~/Animation/MMD/MMDMode_Noop.prefab
Normal 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
|
7
UnitTests~/Animation/MMD/MMDMode_Noop.prefab.meta
Normal file
7
UnitTests~/Animation/MMD/MMDMode_Noop.prefab.meta
Normal file
@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9467ce2e34cfbc74aa9cb6ed1b990488
|
||||
PrefabImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
325
UnitTests~/Animation/MMD/MMDMode_Overrides.prefab
Normal file
325
UnitTests~/Animation/MMD/MMDMode_Overrides.prefab
Normal 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
|
7
UnitTests~/Animation/MMD/MMDMode_Overrides.prefab.meta
Normal file
7
UnitTests~/Animation/MMD/MMDMode_Overrides.prefab.meta
Normal file
@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1880667773f814c49922924e24005b29
|
||||
PrefabImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
454
UnitTests~/Animation/MMD/MMDMode_Reactive.prefab
Normal file
454
UnitTests~/Animation/MMD/MMDMode_Reactive.prefab
Normal 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
|
7
UnitTests~/Animation/MMD/MMDMode_Reactive.prefab.meta
Normal file
7
UnitTests~/Animation/MMD/MMDMode_Reactive.prefab.meta
Normal file
@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 38d357295bfc91b499787e9c3e9e5fc1
|
||||
PrefabImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
340
UnitTests~/Animation/MMD/Overrides.controller
Normal file
340
UnitTests~/Animation/MMD/Overrides.controller
Normal 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:
|
8
UnitTests~/Animation/MMD/Overrides.controller.meta
Normal file
8
UnitTests~/Animation/MMD/Overrides.controller.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9aedd84d3acd0db4384c04f9b136ecb1
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 9100000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
53
UnitTests~/Animation/MMD/empty.anim
Normal file
53
UnitTests~/Animation/MMD/empty.anim
Normal 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: []
|
8
UnitTests~/Animation/MMD/empty.anim.meta
Normal file
8
UnitTests~/Animation/MMD/empty.anim.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 931318d79958463468b9ca3d48c96186
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 7400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -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)
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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 _));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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}
|
@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b64134bbe3efa51449776e476b920317
|
||||
PrefabImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -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}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user