From c07abfdeb0b72ddda7d12b306312b0a5922d4c65 Mon Sep 17 00:00:00 2001 From: Benjythebee Date: Tue, 10 Dec 2024 07:13:25 +1300 Subject: [PATCH] blendshape restriction --- src/library/characterManager.js | 29 +++++++++++++++-- src/library/manifestRestrictions.js | 49 ++++++++++++++++++++++++++--- src/library/utils.js | 4 +-- 3 files changed, 74 insertions(+), 8 deletions(-) diff --git a/src/library/characterManager.js b/src/library/characterManager.js index d0cf894f..6dd20f7d 100644 --- a/src/library/characterManager.js +++ b/src/library/characterManager.js @@ -594,7 +594,7 @@ export class CharacterManager { /** * remove blendshape trait * @param {string} traitGroupID - * @param {string} blendshapeGroupId + * @param {string|null} blendshapeGroupId * @returns */ removeBlendShapeTrait(groupTraitID, blendShapeGroupId){ @@ -630,6 +630,20 @@ export class CharacterManager { return isAllowAggregated.length? isAllowAggregated:[{allowed:true,blocking:{}}] } + /** + * INTERNAL: Check Blendshape restrictions; + * @param {} groupTraitID + */ + _checkBlendshapeRestrictions(groupTraitID){ + for( const trait in this.avatar){ + const p = this.manifestData.manifestRestrictions.restrictionMaps[trait]?.isReverseBlendshapeTraitAllowed(groupTraitID) + if(!p.allowed && p.blockingTrait){ + console.warn(`Trait with name: Blendshapes of ${trait} is not allowed to be loaded with ${groupTraitID}`) + this.removeBlendShapeTrait(trait,null) + } + } + } + /** * INTERNAL: Checks and Remove blocking traits; Used when loading a new trait * @param {string} groupTraitID @@ -639,6 +653,8 @@ export class CharacterManager { const isAllowed = this._getTraitAllowedRules(groupTraitID,traitID) if(isAllowed[0].allowed){ + // check if blendshape restrictions are met + this._checkBlendshapeRestrictions(groupTraitID) return } for(const rule of isAllowed){ @@ -1045,7 +1061,7 @@ export class CharacterManager { /** * * @param {string} traitGroupID - * @param {string} blendshapeGroupId + * @param {string|null} blendshapeGroupId * @param {string|null} blendshapeTraitId * @returns */ @@ -1058,6 +1074,15 @@ export class CharacterManager { if(!currentTrait.blendShapeTraitsInfo){ currentTrait.blendShapeTraitsInfo = {}; } + + if(!blendshapeGroupId){ + for(const k in currentTrait.blendShapeTraitsInfo){ + // Deactivate the current blendshape trait + this.toggleBinaryBlendShape(currentTrait.model, currentTrait.blendShapeTraitsInfo[k], false); + } + return + } + if(currentTrait.blendShapeTraitsInfo[blendshapeGroupId]){ // Deactivate the current blendshape trait this.toggleBinaryBlendShape(currentTrait.model, currentTrait.blendShapeTraitsInfo[blendshapeGroupId], false); diff --git a/src/library/manifestRestrictions.js b/src/library/manifestRestrictions.js index f9cc7bdc..507acd21 100644 --- a/src/library/manifestRestrictions.js +++ b/src/library/manifestRestrictions.js @@ -12,6 +12,7 @@ export class ManifestRestrictions { * @type {Record;} */ traitRestrictions @@ -50,8 +51,9 @@ export class ManifestRestrictions { const log = [] for(const r in this.restrictionMaps){ const restriction = this.restrictionMaps[r] - restriction.restrictedTypes.size && log.push(`Trait: ${restriction.group.trait} is restrciting traits ${Array.from(restriction.restrictedTraits.values()).join(', ')}`) - restriction.restrictedTypes.size && log.push(`Trait: ${restriction.group.trait} also restricts types ${Array.from(restriction.restrictedTypes.values()).join(', ')}`) + restriction.restrictedTraits.size && console.log(`Trait: ${restriction.group.trait} is restrciting ${Array.from(restriction.restrictedTraits.values()).join(', ')}`) + restriction.restrictedTypes.size && console.log(`Trait: ${restriction.group.trait} also restricts types ${Array.from(restriction.restrictedTypes.values()).join(', ')}`) + restriction.restrictedBlendshapes.size && console.log(`Trait: ${restriction.group.trait} has blendshape restrictions on trait ${Array.from(restriction.restrictedBlendshapes.values()).join(', ')}`) } this.itemRestrictions.forEach((v,k)=>{ log.push(`Item ${k} is restricting item ${Array.from(v.values()).join(', ')}`) @@ -176,16 +178,25 @@ export class ManifestRestrictions { * @type {Record} */ const traitRes = {} if (this.traitRestrictions) { for (const prop in this.traitRestrictions) { if (traitRes[prop] == null) { - traitRes[prop] = { restrictedTraits: [], restrictedTypes: [] } + traitRes[prop] = { restrictedTraits: [], restrictedTypes: [], restrictedBlendshapes: [] } } - traitRes[prop].restrictedTraits = getAsArray(this.traitRestrictions[prop].restrictedTraits).filter((t) => !!t); + traitRes[prop].restrictedTraits = getAsArray(this.traitRestrictions[prop].restrictedTraits).map((t)=>{ + if(!this.manifestData.requiredTraits.includes(t)){ + console.warn(`A required trait cannot be a restricted trait. This is because trait A can remove required trait B when A is selected.`) + return t + }else{ + return null + } + }).filter((t) => !!t) traitRes[prop].restrictedTypes = getAsArray(this.traitRestrictions[prop].restrictedTypes).filter((t) => !!t); + traitRes[prop].restrictedBlendshapes = getAsArray(this.traitRestrictions[prop].restrictedBlendshapes).filter((t) => !!t); } } this.traitRestrictions = traitRes @@ -229,6 +240,11 @@ export class TraitRestriction { */ restrictedTypes + /** + * @type {Set} + */ + restrictedBlendshapes + /** * * @param {ManifestRestrictions} manifestRestrictions @@ -240,6 +256,7 @@ export class TraitRestriction { this.restrictedTraits = new Set(this.manifestRestrictions.traitRestrictions[group.trait]?.restrictedTraits || []); this.restrictedTypes = new Set(this.manifestRestrictions.traitRestrictions[group.trait]?.restrictedTypes || []); + this.restrictedBlendshapes = new Set(this.manifestRestrictions.traitRestrictions[group.trait]?.restrictedBlendshapes || []); /** * Check if the current trait is restricting another trait, if so add the current trait to the restrictedTraits list of the other trait @@ -377,4 +394,28 @@ export class TraitRestriction { blockingItemId:isReverseItemAllowed.blockingItemId }} } + + /** + * + * @param {string} traitId + * @returns + */ + isBlendshapeOfTraitAllowed = (traitId) => { + return !this.restrictedBlendshapes.has(traitId); + } + + /** + * Check whether this trait restriction is allowed by target trait + * @param {string} targetTrait + * @returns {TraitRestrictionResult} + */ + isReverseBlendshapeTraitAllowed = (targetTrait) => { + const restriction = this.manifestRestrictions.restrictionMaps[targetTrait]; + if (restriction) { + const isAllowed = restriction.isBlendshapeOfTraitAllowed(this.traitId) + return {allowed:isAllowed, blockingTrait: isAllowed?undefined:this.traitId}; + } + + return {allowed:true, blockingTrait: undefined}; + } } \ No newline at end of file diff --git a/src/library/utils.js b/src/library/utils.js index c082158a..983edbae 100644 --- a/src/library/utils.js +++ b/src/library/utils.js @@ -7,10 +7,10 @@ import { CullHiddenFaces, DisposeCullMesh } from './cull-mesh.js'; import { combine } from "./merge-geometry"; import { VRMLoaderPlugin, VRMUtils } from '@pixiv/three-vrm'; import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader" -import { VRMHumanBoneName, VRMHumanBoneParentMap } from "@pixiv/three-vrm"; +import { VRMHumanBoneName } from "@pixiv/three-vrm"; export function getAsArray(target) { - if (target == null) return [] + if (target == null || target == undefined) return [] return Array.isArray(target) ? target : [target] }