diff --git a/cocos/animation/marionette/pose-graph/instantiation.ts b/cocos/animation/marionette/pose-graph/instantiation.ts index 0b1db72ed13..30b19825d01 100644 --- a/cocos/animation/marionette/pose-graph/instantiation.ts +++ b/cocos/animation/marionette/pose-graph/instantiation.ts @@ -25,6 +25,7 @@ class InstantiatedPoseGraph { constructor ( private _rootPoseNode: PoseNode | undefined, private _countingPlayMotionNodes: readonly PoseNodePlayMotion[] | undefined, + private _allPoseNodes: readonly PoseNode[], ) { } @@ -33,6 +34,14 @@ class InstantiatedPoseGraph { this._rootPoseNode?.bind(context); } + public overrideClips (context: AnimationGraphBindingContext): void { + const { _allPoseNodes: allPoseNodes } = this; + const nNodes = allPoseNodes.length; + for (let iNode = 0; iNode < nNodes; ++iNode) { + allPoseNodes[iNode].overrideClips(context); + } + } + public settle (context: AnimationGraphSettleContext): void { this._rootPoseNode?.settle(context); } @@ -97,6 +106,7 @@ export function instantiatePoseGraph ( return new InstantiatedPoseGraph( undefined, mayCountMotionTime ? [] : undefined, + [], ); } // If the output node has a binding, it must be pose node. @@ -113,11 +123,13 @@ export function instantiatePoseGraph ( ); assertIsTrue(mainRecord instanceof PoseNode); + const allPoseNodes = Array.from(instantiationMap.values()).filter((node): node is PoseNode => node instanceof PoseNode); return new InstantiatedPoseGraph( mainRecord, mayCountMotionTime ? Array.from(instantiationMap.values()).filter((node): node is PoseNodePlayMotion => node instanceof PoseNodePlayMotion) : undefined, + allPoseNodes, ); } @@ -287,6 +299,7 @@ function linkPoseNode ( if (producerOutputIndex !== 0) { // Rule: pose nodes have and only have one output. + // eslint-disable-next-line @typescript-eslint/no-base-to-string warn(`Node ${producerNode.toString()} does not have specified output ${producerOutputIndex}.`); return; } diff --git a/cocos/animation/marionette/pose-graph/pose-node.ts b/cocos/animation/marionette/pose-graph/pose-node.ts index 4dd82a19c29..486e5a92a0e 100644 --- a/cocos/animation/marionette/pose-graph/pose-node.ts +++ b/cocos/animation/marionette/pose-graph/pose-node.ts @@ -51,6 +51,12 @@ export abstract class PoseNode extends PoseGraphNode { */ public abstract settle (context: AnimationGraphSettleContext): void; + /** + * Rebinds motions when clip overrides on the binding context change. + * Pose nodes that own motion evaluations or nested graphs override this. + */ + public overrideClips (_context: AnimationGraphBindingContext): void {} + /** * Reenter this pose nodes. * @@ -94,12 +100,16 @@ export abstract class PoseNode extends PoseGraphNode { if (POSE_NODE_EVALUATION_STACK_ORDER_DEBUG_ENABLED) { // The stack should certainly increase 1. - assertIsTrue(context._stackSize_debugging === stackSizeBefore + 1, - `PoseNode.doEvaluate() should certainly push a pose node onto the stack and return it.`); + assertIsTrue( + context._stackSize_debugging === stackSizeBefore + 1, + `PoseNode.doEvaluate() should certainly push a pose node onto the stack and return it.`, + ); // The returned pose should be the increased pose, that's, // can not return a already-popped pose. - assertIsTrue(context._isStackTopPose_debugging(pose), - `PoseNode.doEvaluate() should certainly push a pose node onto the stack and return it.`); + assertIsTrue( + context._isStackTopPose_debugging(pose), + `PoseNode.doEvaluate() should certainly push a pose node onto the stack and return it.`, + ); } const currentSpace = pose._poseTransformSpace; diff --git a/cocos/animation/marionette/pose-graph/pose-nodes/play-motion.ts b/cocos/animation/marionette/pose-graph/pose-nodes/play-motion.ts index 9560ac9a3fe..4983d0b95ed 100644 --- a/cocos/animation/marionette/pose-graph/pose-nodes/play-motion.ts +++ b/cocos/animation/marionette/pose-graph/pose-nodes/play-motion.ts @@ -1,5 +1,5 @@ import { EDITOR } from 'internal:constants'; -import { ccclass, displayName, editable, serializable, unit } from '../../../../core/data/decorators'; +import { ccclass, editable, serializable, unit } from '../../../../core/data/decorators'; import { CLASS_NAME_PREFIX_ANIM } from '../../../define'; import { ClipMotion } from '../../motion/clip-motion'; import { createEval } from '../../create-eval'; @@ -79,6 +79,10 @@ export class PoseNodePlayMotion extends PoseNode { } } + public overrideClips (context: AnimationGraphBindingContext): void { + this._workspace?.motionEval.overrideClips(context); + } + public settle (context: AnimationGraphSettleContext): void { // override } diff --git a/cocos/animation/marionette/pose-graph/pose-nodes/sample-motion.ts b/cocos/animation/marionette/pose-graph/pose-nodes/sample-motion.ts index fac5e8fe16f..b7eb175e78e 100644 --- a/cocos/animation/marionette/pose-graph/pose-nodes/sample-motion.ts +++ b/cocos/animation/marionette/pose-graph/pose-nodes/sample-motion.ts @@ -51,6 +51,10 @@ export class PoseNodeSampleMotion extends PoseNode { this._workspace = workspace; } + public overrideClips (context: AnimationGraphBindingContext): void { + this._workspace?.motionEval.overrideClips(context); + } + public settle (context: AnimationGraphSettleContext): void { // Do nothing. } diff --git a/cocos/animation/marionette/pose-graph/pose-nodes/state-machine.ts b/cocos/animation/marionette/pose-graph/pose-nodes/state-machine.ts index 35e0122e9f1..71597793ee1 100644 --- a/cocos/animation/marionette/pose-graph/pose-nodes/state-machine.ts +++ b/cocos/animation/marionette/pose-graph/pose-nodes/state-machine.ts @@ -45,6 +45,10 @@ export class PoseNodeStateMachine extends PoseNode { ); } + public overrideClips (context: AnimationGraphBindingContext): void { + this._stateMachineEval?.overrideClips(context); + } + public settle (context: AnimationGraphSettleContext): void { this._stateMachineEval?.settle(context); } diff --git a/cocos/animation/marionette/state-machine/state-machine-eval.ts b/cocos/animation/marionette/state-machine/state-machine-eval.ts index 9536abb54f4..8d020a9946d 100644 --- a/cocos/animation/marionette/state-machine/state-machine-eval.ts +++ b/cocos/animation/marionette/state-machine/state-machine-eval.ts @@ -6,7 +6,7 @@ import { } from '../animation-graph'; import { MotionEval, MotionPort } from '../motion'; import { createEval } from '../create-eval'; -import { BindContext, validateVariableExistence, validateVariableType, VariableType } from '../parametric'; +import { validateVariableExistence, validateVariableType, VariableType } from '../parametric'; import { ConditionEval, TriggerCondition } from './condition'; import { MotionState } from './motion-state'; import { warnID, assertIsTrue, assertIsNonNullable, Pool, approx, clamp01 } from '../../../core'; @@ -21,10 +21,8 @@ import { TriggerResetter, } from '../animation-graph-context'; import { blendPoseInto, Pose } from '../../core/pose'; -import { PoseNode } from '../pose-graph/pose-node'; import { instantiatePoseGraph, InstantiatedPoseGraph } from '../pose-graph/instantiation'; import { ConditionEvaluationContext } from './condition/condition-base'; -import { ReadonlyClipOverrideMap } from '../clip-overriding'; import { AnimationGraphEventBinding } from '../event/event-binding'; /** @@ -257,6 +255,11 @@ class TopLevelStateMachineEvaluation { const node = motionStates[iMotionState]; node.overrideClips(context); } + const { _proceduralPoseStates: proceduralPoseStates } = this; + const nProcedural = proceduralPoseStates.length; + for (let iProcedural = 0; iProcedural < nProcedural; ++iProcedural) { + proceduralPoseStates[iProcedural].overrideClips(context); + } } private declare _controller: AnimationController; @@ -1451,6 +1454,10 @@ class ProceduralPoseStateEval extends EventifiedStateEval { return this._instantiatedPoseGraph.countMotionTime(); } + public overrideClips (context: AnimationGraphBindingContext): void { + this._instantiatedPoseGraph.overrideClips(context); + } + private _instantiatedPoseGraph: InstantiatedPoseGraph; private readonly _statusCache: MotionStateStatus = createStateStatusCache();