UNPKG

sandai-react

Version:

React components and utilities for the Sandai 3D AI Characters.

177 lines 6.92 kB
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