@awayjs/graphics
Version:
AwayJS graphics classes
194 lines (156 loc) • 5.76 kB
text/typescript
import { Vector3D } from '@awayjs/core';
import { JointPose } from '../data/JointPose';
import { Skeleton } from '../data/Skeleton';
import { SkeletonPose } from '../data/SkeletonPose';
import { SkeletonDirectionalNode } from '../nodes/SkeletonDirectionalNode';
import { AnimationStateBase } from './AnimationStateBase';
import { ISkeletonAnimationState } from './ISkeletonAnimationState';
import { AnimatorBase } from '../AnimatorBase';
/**
*
*/
export class SkeletonDirectionalState extends AnimationStateBase implements ISkeletonAnimationState {
private _skeletonAnimationNode: SkeletonDirectionalNode;
private _skeletonPose: SkeletonPose = new SkeletonPose();
private _skeletonPoseDirty: boolean = true;
private _inputA: ISkeletonAnimationState;
private _inputB: ISkeletonAnimationState;
private _blendWeight: number = 0;
private _direction: number = 0;
private _blendDirty: boolean = true;
private _forward: ISkeletonAnimationState;
private _backward: ISkeletonAnimationState;
private _left: ISkeletonAnimationState;
private _right: ISkeletonAnimationState;
/**
* Defines the direction in degrees of the aniamtion between the forwards (0), right(90) backwards (180) and left(270) input nodes,
* used to produce the skeleton pose output.
*/
public set direction(value: number) {
if (this._direction == value)
return;
this._direction = value;
this._blendDirty = true;
this._skeletonPoseDirty = true;
this._pPositionDeltaDirty = true;
}
public get direction(): number {
return this._direction;
}
constructor(animator: AnimatorBase, skeletonAnimationNode: SkeletonDirectionalNode) {
super(animator, skeletonAnimationNode);
this._skeletonAnimationNode = skeletonAnimationNode;
this._forward = <ISkeletonAnimationState> animator.getAnimationState(this._skeletonAnimationNode.forward);
this._backward = <ISkeletonAnimationState> animator.getAnimationState(this._skeletonAnimationNode.backward);
this._left = <ISkeletonAnimationState> animator.getAnimationState(this._skeletonAnimationNode.left);
this._right = <ISkeletonAnimationState> animator.getAnimationState(this._skeletonAnimationNode.right);
}
/**
* @inheritDoc
*/
public phase(value: number): void {
if (this._blendDirty)
this.updateBlend();
this._skeletonPoseDirty = true;
this._pPositionDeltaDirty = true;
this._inputA.phase(value);
this._inputB.phase(value);
}
/**
* @inheritDoc
*/
public _pUdateTime(time: number): void {
if (this._blendDirty)
this.updateBlend();
this._skeletonPoseDirty = true;
this._inputA.update(time);
this._inputB.update(time);
super._pUpdateTime(time);
}
/**
* Returns the current skeleton pose of the animation in the clip based on the internal playhead position.
*/
public getSkeletonPose(skeleton: Skeleton): SkeletonPose {
if (this._skeletonPoseDirty)
this.updateSkeletonPose(skeleton);
return this._skeletonPose;
}
/**
* @inheritDoc
*/
public _pUpdatePositionDelta(): void {
this._pPositionDeltaDirty = false;
if (this._blendDirty)
this.updateBlend();
const deltA: Vector3D = this._inputA.positionDelta;
const deltB: Vector3D = this._inputB.positionDelta;
this.positionDelta.x = deltA.x + this._blendWeight * (deltB.x - deltA.x);
this.positionDelta.y = deltA.y + this._blendWeight * (deltB.y - deltA.y);
this.positionDelta.z = deltA.z + this._blendWeight * (deltB.z - deltA.z);
}
/**
* Updates the output skeleton pose of the node based on the direction value between forward, backwards, left and right input nodes.
*
* @param skeleton The skeleton used by the animator requesting the ouput pose.
*/
private updateSkeletonPose(skeleton: Skeleton): void {
this._skeletonPoseDirty = false;
if (this._blendDirty)
this.updateBlend();
let endPose: JointPose;
const endPoses: Array<JointPose> = this._skeletonPose.jointPoses;
const poses1: Array<JointPose> = this._inputA.getSkeletonPose(skeleton).jointPoses;
const poses2: Array<JointPose> = this._inputB.getSkeletonPose(skeleton).jointPoses;
let pose1: JointPose, pose2: JointPose;
let p1: Vector3D, p2: Vector3D;
let tr: Vector3D;
const numJoints: number = skeleton.numJoints;
// :s
if (endPoses.length != numJoints)
endPoses.length = numJoints;
for (let i: number = 0; i < numJoints; ++i) {
endPose = endPoses[i];
if (endPose == null)
endPose = endPoses[i] = new JointPose();
pose1 = poses1[i];
pose2 = poses2[i];
p1 = pose1.translation;
p2 = pose2.translation;
endPose.orientation.lerp(pose1.orientation, pose2.orientation, this._blendWeight);
tr = endPose.translation;
tr.x = p1.x + this._blendWeight * (p2.x - p1.x);
tr.y = p1.y + this._blendWeight * (p2.y - p1.y);
tr.z = p1.z + this._blendWeight * (p2.z - p1.z);
}
}
/**
* Updates the blend value for the animation output based on the direction value between forward, backwards, left and right input nodes.
*
* @private
*/
private updateBlend(): void {
this._blendDirty = false;
if (this._direction < 0 || this._direction > 360) {
this._direction %= 360;
if (this._direction < 0)
this._direction += 360;
}
if (this._direction < 90) {
this._inputA = this._forward;
this._inputB = this._right;
this._blendWeight = this._direction / 90;
} else if (this._direction < 180) {
this._inputA = this._right;
this._inputB = this._backward;
this._blendWeight = (this._direction - 90) / 90;
} else if (this._direction < 270) {
this._inputA = this._backward;
this._inputB = this._left;
this._blendWeight = (this._direction - 180) / 90;
} else {
this._inputA = this._left;
this._inputB = this._forward;
this._blendWeight = (this._direction - 270) / 90;
}
}
}