sandai-react
Version:
React components and utilities for the Sandai 3D AI Characters.
177 lines • 6.92 kB
TypeScript
import { VRM } from "@pixiv/three-vrm";
import * as THREE from "three";
import { MouthExpressionManager, MouthExpression } from "./MouthExpressionManager.ts";
import { FaceExpressionManager, FaceExpression } from "./FaceExpressionManager.ts";
import { MotionExpressionManager, MotionExpression } from "./MotionExpressionManager.ts";
import { MotionConversionWorkerClient } from "./MotionExpressionWorkerClient.ts";
import { Observable } from "rxjs";
export declare class LoopType {
static FastForward: number;
static Repeat: number;
static Once: number;
}
export declare class InterpolationType {
static discrete: number;
static linear: number;
static smooth: number;
}
export declare class AnimationBlendType {
static normal: number;
static additive: number;
}
export interface ExpressionOptions {
interpolationMode: THREE.InterpolationModes;
animationBlendMode: THREE.AnimationBlendMode;
smoothing: number;
bodySmoothing: number;
headSmoothing: number;
faceSmoothing: number;
armsSmoothing: number;
legsSmoothing: number;
handsSmoothing: number;
}
export interface ExpressionInput {
/**
* ```ts
* FaceExpression {
* duration: number;
* angry?: number; // between 0 and 1
* happy?: number; // between 0 and 1
* neutral?: number; // between 0 and 1
* relaxed?: number; // between 0 and 1
* sad?: number; // between 0 and 1
* surprised?: number; // between 0 and 1
* }
* ```
*/
faceExpressions?: FaceExpression[];
/**
* ```ts
* MouthExpression {
* duration: number;
* aa?: number; // between 0 and 1
* ee?: number; // between 0 and 1
* ih?: number; // between 0 and 1
* oh?: number; // between 0 and 1
* ou?: number; // between 0 and 1
* }
* ```
*/
mouthExpressions?: MouthExpression[];
/**
* ```ts
* MotionExpression {
* clip: THREE.AnimationClip;
* duration?: number; // will default to clip duration if not provided
* }
* ```
*/
motionExpressions?: MotionExpression[];
/**
* 1001: FastForward
*
* 2201: THREE.LoopRepeat
*
* 2200: THREE.LoopOnce
*/
loopMotion?: LoopType;
opt?: ExpressionOptions;
}
export declare class ExpressionManager {
mouth: MouthExpressionManager;
face: FaceExpressionManager;
motion: MotionExpressionManager;
_vrm: VRM;
/** Expressions that should be decoupled by default. For example,
* the "happy" expression should not control the same vertices as
* the "blink" expression, as the eyes would close, if the "happy"
* expression is detected, meaning that the person in the video
* feed might not have their eyes closed, but the model would.
*
* This applies to "aa", "ee", "ih", "oh", "ou", "blinkLeft" and
* "blinkRight" as well
*/
static defaultDecouplables: [string, string, number][];
private _vrmUrl;
private _expressionOverlaps;
private _expressionStreams;
private _expressionResetters;
/**
* Used to store the original geometires before other expressions are decoupled.
*/
private _initialExpressoinGeometries;
constructor(vrm: VRM, vrmUrl: string, motionConversionWorkerClient?: MotionConversionWorkerClient);
_express(expressionInput: ExpressionInput, opt?: {
skipMotionSubscription?: boolean;
skipMouthSubscription?: boolean;
skipFaceSubscription?: boolean;
}): Observable<MotionExpression | FaceExpression | MouthExpression>;
express(expressionInput: ExpressionInput, opt?: {
skipMotionSubscription?: boolean;
skipMouthSubscription?: boolean;
skipFaceSubscription?: boolean;
}): Observable<MotionExpression | FaceExpression | MouthExpression>;
/**
* 3D artists have the unfortunate habit of creating models that
* have broken blendshapes when combined. The most common example
* is opening the mouth for the 'happy' shapekey.
*
* While the mistake is understandable, it leads to various issues,
* like the mouth not opening when an emotion targets the mouth
* vertices and has them closed or the mouth being wide open
* whenever a model displays an emotion that has been mapped
* to an open mouth, breaking mouth movements.
*
* This decouples those vertices as best as possible, but really it
* is the models that need to be fixed.
*
* Honestly if something like lip-sync doesn't work, it is more likely
* to be an issue with the model than with the underlying implementation.
*
* I spent countless days trying to debug phantom-issues like these
* only to discover that the models were broken.
*
* Don't be like me, check the models first, then check if the issue
* exists after you called this function, and then you can come
* and bash my head in if it still doesn't work.
*/
decoupleCommonBrokenBlendshapes(): void;
/**
* If you previously called [decoupleCommonBrokenBlendshapes], you can run
* this to undo the decoupling
*/
recoupleCommonBrokenBlendshapes(): void;
private findOverlappingExpressions;
private findExpressionVertexDeltas;
private markGeometryForUpdate;
private cloneMorphGeometry;
private ensureInitialGeometryStored;
/**
* Decouples overlapping expressions.
*
* If two expressions target the same vertices (e.g. "happy" and "blink" both close the eyes),
* you can pass the expression you want to stop targeting the overlapping vertices as the target
* expression and the expression that targets these vertices more precisely as the delta expression.
*
* For example, if you model closes it's eyes when set to {happy: 1} and you want the eyes to be
* unaffected, you'd pass:
* ```js
* decoupleExpression("happy", "blink");
* ```
*
* @param targetExpression The expression to decouple from
* @param deltaExpression The expression that overlaps with the target expression
* @param withDelta The delta to determine the degree of overlap. If you're
* not sure what this should be, the default is set reasonably.
* If you're model closes it's eyes when set to "happy" for example, but you want
* the eyes to be unaffected, you'd pass "blink" as the delta expression. If "happy"
* then still influences the eyes, you should increase this delta value and see which
* value works best for your model.
* @returns void
*/
decoupleExpression(targetExpression: string, deltaExpression: string, withDelta?: number): void;
recoupleExpression(expressionKey: string): void;
update(delta: number): void;
destroy(): void;
}
//# sourceMappingURL=ExpressionManager.d.ts.map