-
Notifications
You must be signed in to change notification settings - Fork 309
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
モーフィング機能の制限に対応 #1128
モーフィング機能の制限に対応 #1128
Conversation
@Hiroshiba |
src/components/AudioInfo.vue
Outdated
}, | ||
}; | ||
}).filter((characters) => characters.metas.styles.length >= 1), | ||
]; | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
もう1つUXレベルの判断です。 (実装してくださった @sabonerune さんの感謝も込めて・・・! )
今まででは全キャラ全スタイルが表示されていたのが、ここで可能なキャラだけになります。
そもそもですが、ボイボは8割のキャラが8割のキャラとモーフィング可能で、2割のキャラはほぼ不可となりそうです。
仕様としてどの形が良いか考えてみました。
最高なのはこうだと思います。
- 選択可能なキャラが上に表示
- 不可能なキャラが下に表示
- 選択不可能な理由が書いてある
このパターンだと3番目の選択不可能な理由を書けるUIの用意が大変だと思いました。
次はこうかなと思います。
- 選択可能なキャラだけが表示されている
- 表示されないキャラクターがいることの理由がわかる
理由の表示はここのUIでできるとベターだと思いますが、なかなか案内が難しそうに感じます。
良い方法がない場合はQ&A+使い方で案内が良いかなと思いました。
なぜ全キャラを選択できるUIが厳しいのかというと、全キャラが選択不可能なキャラもいることがわかったためです。
このキャラを選んでいた場合の運の悪いユーザーのパターンだと、全キャラの選択を試して、全キャラダメだったとわかるというなかなかしんどそうなUXになってしまうためです。
元のUIがよくないわけではなく、想定が変わったことが今回の判断の変更理由になります。
もっと良い形もあるかもしれません、アイデア募集しています・・・!!!
src/store/audio.ts
Outdated
(characterInfo) => characterInfo.metas.styles | ||
); | ||
const styleIds = styles.map((style) => style.styleId); | ||
const morphablePairInfo = Object.fromEntries( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ここの二重ループはちょっとなんとかしたみがありますね 😇
とりあえず実際のエンジンで動かしてみて、まあ数秒で終わるならとりあえずこの実装で良いのかなと思いました!
そうじゃなかった場合は、エンジンAPIのisMorphableIsMorphableGet
に、複数ペアを投げられるようにするのが良いのかなと思いました!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
それでもGETクエリがとんでもない長さになりますね・・・・。
複数ペア投げられるようにし、キャラやスタイルが変わるたびにGETを投げるのはどうでしょうか。(N^1になる)
もしエンジン側の処理が重ければエディタ側でキャッシュするのも考えて良いかもです。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
試してみたところ、2000近いリクエストが同時に投げられる為一部のリクエスト以外失敗してしまうようでした.
/is_morphable
APIのようなスタイル-スタイル間のモーフィング可否ではなく、1スタイルに対してエンジン内の各スタイルがモーフィング可能かどうか返すmorphable_targets
APIを生やしてリクエスト数を減らすとともに、固定サイズのLRUキャッシュで遂次取ってくる形に変えたいと思います.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
おっと、なるほどです。
提案の形、とても良いなと感じました!!ぜひよろしくお願いします 🙇♂️
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
実装ありがとうございます!!!
いろいろコメントしましたが、ペアを作る部分に関しては実際に動かしてみてからかなと思いました!!
@Segu-g モーフィング周り追加でお任せしちゃっても大丈夫ですか🙇♂️ |
@@ -1117,7 +1237,18 @@ export const audioStore = createPartialStore<AudioStoreTypes>({ | |||
let blob: Blob; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
この関数の上でgetters
が使われてないというwarningが出てました。(githubの仕様でそこにコメントできず。。)
morphableTargetsInfo: Record<string, MorphableTargetsInfo>; | ||
morphableTargetsCacheKey: Record<string, Array<number>>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
numberになっているため何の値が入ってるか混乱しそうです。こうするとちょっとマシかも。
morphableTargetsInfo: Record<string, MorphableTargetsInfo>; | |
morphableTargetsCacheKey: Record<string, Array<number>>; | |
morphableTargetsInfo: Record<string, MorphableTargetsInfo>; | |
morphableTargetsCacheStyleIds: Record<string, Array<number>>; |
@@ -310,6 +310,16 @@ export type PresetConfig = { | |||
keys: string[]; | |||
}; | |||
|
|||
export type MorphableTargetsInfo = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s要らないかも?
export type MorphableTargetsInfo = { | |
export type MorphableTargetInfo = { |
SET_MORPHABLE_TARGETS: { | ||
mutation(state, { engineId, baseStyleId, morphableTargets }) { | ||
const prevIndex = state.morphableTargetsCacheKey[engineId].findIndex( | ||
(styleId) => styleId === baseStyleId | ||
); | ||
if (prevIndex < 0 && morphableTargets) { | ||
state.morphableTargetsCacheKey[engineId].splice(0, 0, baseStyleId); | ||
// キャッシュ上限を超えた場合は削除する | ||
if ( | ||
state.morphableTargetsCacheKey[engineId].length > | ||
MORPHABLE_CACHE_LIMIT | ||
) { | ||
const postStyleId = state.morphableTargetsCacheKey[engineId].pop(); | ||
if (postStyleId !== undefined) { | ||
delete state.morphableTargetsInfo[engineId][postStyleId]; | ||
} | ||
} | ||
state.morphableTargetsInfo[engineId][baseStyleId] = morphableTargets; | ||
} else { | ||
state.morphableTargetsCacheKey[engineId].splice(prevIndex, 1); | ||
state.morphableTargetsCacheKey[engineId].splice(0, 0, baseStyleId); | ||
if (morphableTargets) | ||
state.morphableTargetsInfo[engineId][baseStyleId] = morphableTargets; | ||
} | ||
}, | ||
}, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
このままでも全く問題ないのですが(正直ちゃんと追えてません。。)、ちょっと調べてみた感じMapは順序を持てることが保証されてるので結構簡単にキャッシュ機構を作れるっぽかったです。
ご興味あれば・・・!
const prevIndex = state.morphableTargetsCacheKey[engineId].findIndex( | ||
(styleId) => styleId === baseStyleId | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
indexOfでも良さそう?
const prevIndex = state.morphableTargetsCacheKey[engineId].findIndex( | |
(styleId) => styleId === baseStyleId | |
); | |
const prevIndex = state.morphableTargetsCacheKey[engineId].indexOf(baseStyleId); |
return morphableTargets === undefined | ||
? !strictCache | ||
: morphableTargets[targetVoice.styleId]?.isMorphable; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
morphableTargets[targetVoice.styleId]?.isMorphable
のところ、undefined | boolean
が返ってそうですね 😇
意図をわかりやすくするとこうですかね(あまり変わってないかも)
return morphableTargets === undefined | |
? !strictCache | |
: morphableTargets[targetVoice.styleId]?.isMorphable; | |
if (morphableTargets == undefined) { return !strictCache; } | |
return morphableTargets[targetVoice.styleId]?.isMorphable == true |
/** | ||
* 引数の2つのVoiceがモーフィング可能かどうか返す。 | ||
* strictCacheがtrueのときキャッシュが存在しない場合は不可とされる。 | ||
*/ | ||
IS_A_VALID_MOPHING_PAIR: { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
「キャッシュが無いと不可とされる」の意図がわからなかったのですが、つまり「エンジンに問い合わせなくても無効だとわかる」という意味だったんですね!!!!!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
strictCacheはキャッシュが存在しない場合に楽観的にvalidと判断するか、それとも悲観的にinvalidと判断するかを変更するフラグです。
strictCacheをfalseにした場合楽観的に判断され、trueにした場合悲観的に判断されます。
"""楽観的な判断でinvalidと判断された場合、キャッシュが存在したとしてもtrueになることはないのでエンジンに問い合わせなくても無効だと分かる"""、という意味で書かれているのがこの部分のコードです。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
なるほどです。
意図はわかるのですが、キャッシュの仕様がこの関数内に無いので、キャッシュstateによってこの関数の挙動が変わることになりそうです。
この関数の利用者はキャッシュにあまり興味が無いはずなのに、キャッシュの有無による挙動の制御をすることになり大変だなと思った次第です。
たぶん役割の違う関数2つがまとまっているから難しくなっているのかなと思いました!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ちょっと全部見きれてないです! 🙇♂️
このままでもたぶん良いのかなと思いつつ、流石にちょっと複雑かもと感じました。
またあとで見てみますが、ちょっと設計を考えてみたのでもし気が向いたら考えてみて頂けると・・・・・・・!!
INVALIDなのを弾くのではなく、VALIDなのを集める設計が良いのかなと思いました。
となると、同一エンジンでmophableTargetを取ってきたのを表示すればいいだけになりそうです。
(IS_A_VALID_MOPHING_PAIR
を不要にできるはず)
あとINITIALIZE_MORPHABLE_TARGETS
はSET_MORPHABLE_TARGETS
するときに空だったら足す処理書くと消せるかもです。(好みがありそう)
いまさらなのですが、キャラ選択ボタンは選択後にモデルを読み込むからloading機能があることに気づきました。
これらを組み合わせると
- キャッシュがあれば取得しなければ問い合わせてmophableを返すaction
- キャッシュをセットするmutation
- キャッシュを管理するstate
の3つで実現できるかもです。
・・・だいぶ自信ないです。
またあとで見たいと思います。もし興味あったら考えてみていただければ!!!
こちらのPRですが今日明日に学業の方で喫緊のタスクが入り手を付けられそうにないので、中途半端になりますが残りの修正お任せしたいです🙇♂️ |
@Segu-g おお!!連絡ありがとうございます、承知しました!! |
@Segu-g さん ちょっと思ってた実装と離れちゃってたらすみません。 |
内容
で対応したモーフィング機能の許可に対応
元のUIとの差分として
が生じます。
関連 Issue
スクリーンショット・動画など
その他