@pmndrs/viverse 0.2.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/animation/bone-map.d.ts +4 -0
- package/dist/animation/bone-map.js +11 -0
- package/dist/animation/default.d.ts +9 -1
- package/dist/animation/default.js +16 -9
- package/dist/animation/index.d.ts +8 -13
- package/dist/animation/index.js +61 -39
- package/dist/animation/mask.d.ts +4 -1
- package/dist/animation/mask.js +50 -0
- package/dist/camera.d.ts +6 -2
- package/dist/camera.js +22 -7
- package/dist/input/action.d.ts +41 -0
- package/dist/input/action.js +97 -0
- package/dist/input/index.d.ts +12 -26
- package/dist/input/index.js +17 -70
- package/dist/input/keyboard.d.ts +28 -5
- package/dist/input/keyboard.js +83 -69
- package/dist/input/pointer-capture.d.ts +5 -10
- package/dist/input/pointer-capture.js +9 -28
- package/dist/input/pointer-lock.d.ts +5 -10
- package/dist/input/pointer-lock.js +7 -28
- package/dist/input/screen-joystick.d.ts +11 -6
- package/dist/input/screen-joystick.js +31 -34
- package/dist/input/screen-jump-button.d.ts +2 -4
- package/dist/input/screen-jump-button.js +7 -12
- package/dist/model/index.d.ts +1 -2
- package/dist/simple-character/apply-input-options.d.ts +2 -0
- package/dist/simple-character/apply-input-options.js +28 -0
- package/dist/simple-character/index.d.ts +21 -6
- package/dist/simple-character/index.js +12 -17
- package/dist/simple-character/state/jump-down.js +2 -1
- package/dist/simple-character/state/jump-forward.js +4 -2
- package/dist/simple-character/state/jump-loop.js +2 -1
- package/dist/simple-character/state/jump-start.js +2 -2
- package/dist/simple-character/state/jump-up.js +4 -2
- package/dist/simple-character/state/movement.js +12 -8
- package/dist/simple-character/update-input-velocity.d.ts +1 -2
- package/dist/simple-character/update-input-velocity.js +4 -4
- package/dist/utils.d.ts +5 -5
- package/dist/utils.js +15 -6
- package/package.json +2 -2
- package/dist/animation/bvh.d.ts +0 -4
- package/dist/animation/bvh.js +0 -8
- package/dist/animation/fbx.d.ts +0 -4
- package/dist/animation/fbx.js +0 -8
- package/dist/animation/gltf.d.ts +0 -3
- package/dist/animation/gltf.js +0 -8
- package/dist/animation/vrma.d.ts +0 -3
- package/dist/animation/vrma.js +0 -8
package/dist/model/index.d.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { AnimationAction, AnimationMixer, Object3D, Quaternion } from 'three';
|
|
2
|
-
import { CharacterAnimationMask } from '../animation/index.js';
|
|
3
2
|
export { VRMHumanBoneName } from '@pixiv/three-vrm';
|
|
4
3
|
export * from './vrm.js';
|
|
5
4
|
export type CharacterModelOptions = {
|
|
@@ -23,7 +22,7 @@ export declare function flattenCharacterModelOptions(options: Exclude<CharacterM
|
|
|
23
22
|
export type CharacterModel = {
|
|
24
23
|
mixer: AnimationMixer;
|
|
25
24
|
scene: Object3D;
|
|
26
|
-
currentAnimations: Map<
|
|
25
|
+
currentAnimations: Map<string | undefined, AnimationAction>;
|
|
27
26
|
boneRotationOffset?: Quaternion;
|
|
28
27
|
};
|
|
29
28
|
export declare function loadCharacterModel(url?: string, type?: Exclude<CharacterModelOptions, boolean>['type'], boneRotationOffset?: Quaternion, castShadow?: boolean, receiveShadow?: boolean): Promise<CharacterModel>;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { DefaultJumpKeys, DefaultMoveBackwardKeys, DefaultMoveForwardKeys, DefaultMoveLeftKeys, DefaultMoveRightKeys, DefaultRunKeys, LocomotionKeyboardInput, } from '../input/keyboard.js';
|
|
2
|
+
import { PointerCaptureInput } from '../input/pointer-capture.js';
|
|
3
|
+
import { PointerLockInput } from '../input/pointer-lock.js';
|
|
4
|
+
import { ScreenJoystickInput } from '../input/screen-joystick.js';
|
|
5
|
+
export function applySimpleCharacterInputOptions(inputs, options) {
|
|
6
|
+
for (const input of inputs) {
|
|
7
|
+
if (input instanceof ScreenJoystickInput) {
|
|
8
|
+
input.options.deadZonePx = options?.screenJoystickDeadZonePx;
|
|
9
|
+
input.options.runDistancePx = options?.screenJoystickRunDistancePx;
|
|
10
|
+
}
|
|
11
|
+
if (input instanceof PointerCaptureInput) {
|
|
12
|
+
input.options.rotationSpeed = options?.pointerCaptureRotationSpeed;
|
|
13
|
+
input.options.zoomSpeed = options?.pointerCaptureZoomSpeed;
|
|
14
|
+
}
|
|
15
|
+
if (input instanceof PointerLockInput) {
|
|
16
|
+
input.options.rotationSpeed = options?.pointerLockRotationSpeed;
|
|
17
|
+
input.options.zoomSpeed = options?.pointerLockZoomSpeed;
|
|
18
|
+
}
|
|
19
|
+
if (input instanceof LocomotionKeyboardInput) {
|
|
20
|
+
input.forward.options.keys = options?.keyboardMoveForwardKeys ?? DefaultMoveForwardKeys;
|
|
21
|
+
input.backward.options.keys = options?.keyboardMoveBackwardKeys ?? DefaultMoveBackwardKeys;
|
|
22
|
+
input.left.options.keys = options?.keyboardMoveLeftKeys ?? DefaultMoveLeftKeys;
|
|
23
|
+
input.right.options.keys = options?.keyboardMoveRightKeys ?? DefaultMoveRightKeys;
|
|
24
|
+
input.run.options.keys = options?.keyboardRunKeys ?? DefaultRunKeys;
|
|
25
|
+
input.jump.options.keys = options?.keyboardJumpKeys ?? DefaultJumpKeys;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
import { Group, Object3D, Object3DEventMap, AnimationAction } from 'three';
|
|
2
2
|
import { CharacterAnimationOptions } from '../animation/index.js';
|
|
3
3
|
import { CharacterCameraBehavior, SimpleCharacterCameraBehaviorOptions } from '../camera.js';
|
|
4
|
-
import { Input, ScreenJoystickInputOptions, LocomotionKeyboardInputOptions, PointerCaptureInputOptions, PointerLockInputOptions, InputSystem } from '../input/index.js';
|
|
5
4
|
import { CharacterModelOptions, CharacterModel } from '../model/index.js';
|
|
6
5
|
import { BvhCharacterPhysicsOptions, BvhCharacterPhysics, BvhPhysicsWorld } from '../physics/index.js';
|
|
7
6
|
export type SimpleCharacterState = {
|
|
8
7
|
camera: Object3D;
|
|
9
8
|
model?: CharacterModel;
|
|
10
9
|
physics: BvhCharacterPhysics;
|
|
11
|
-
inputSystem: InputSystem;
|
|
12
10
|
lastJump: number;
|
|
13
11
|
};
|
|
14
12
|
export type SimpleCharacterMovementOptions = {
|
|
@@ -63,10 +61,25 @@ export type SimpleCharacterAnimationOptions = {
|
|
|
63
61
|
*/
|
|
64
62
|
crossFadeDuration?: number;
|
|
65
63
|
};
|
|
66
|
-
export type SimpleCharacterInputOptions =
|
|
64
|
+
export type SimpleCharacterInputOptions = {
|
|
65
|
+
screenJoystickRunDistancePx?: number;
|
|
66
|
+
screenJoystickDeadZonePx?: number;
|
|
67
|
+
pointerCaptureRotationSpeed?: number;
|
|
68
|
+
pointerCaptureZoomSpeed?: number;
|
|
69
|
+
pointerLockRotationSpeed?: number;
|
|
70
|
+
pointerLockZoomSpeed?: number;
|
|
71
|
+
keyboardMoveForwardKeys?: Array<string>;
|
|
72
|
+
keyboardMoveBackwardKeys?: Array<string>;
|
|
73
|
+
keyboardMoveLeftKeys?: Array<string>;
|
|
74
|
+
keyboardMoveRightKeys?: Array<string>;
|
|
75
|
+
keyboardRunKeys?: Array<string>;
|
|
76
|
+
keyboardJumpKeys?: Array<string>;
|
|
77
|
+
};
|
|
67
78
|
export type SimpleCharacterOptions = {
|
|
68
|
-
readonly input?: ReadonlyArray<
|
|
69
|
-
new (domElement: HTMLElement):
|
|
79
|
+
readonly input?: ReadonlyArray<{
|
|
80
|
+
new (domElement: HTMLElement): {
|
|
81
|
+
dispose(): void;
|
|
82
|
+
};
|
|
70
83
|
}>;
|
|
71
84
|
inputOptions?: SimpleCharacterInputOptions;
|
|
72
85
|
movement?: SimpleCharacterMovementOptions;
|
|
@@ -83,7 +96,6 @@ export declare class SimpleCharacter extends Group<Object3DEventMap & {
|
|
|
83
96
|
private readonly options;
|
|
84
97
|
readonly cameraBehavior: CharacterCameraBehavior;
|
|
85
98
|
readonly physics: BvhCharacterPhysics;
|
|
86
|
-
readonly inputSystem: InputSystem;
|
|
87
99
|
readonly currentAnimationRef: {
|
|
88
100
|
current?: AnimationAction;
|
|
89
101
|
};
|
|
@@ -91,7 +103,9 @@ export declare class SimpleCharacter extends Group<Object3DEventMap & {
|
|
|
91
103
|
private readonly updateTimeline;
|
|
92
104
|
private readonly graph;
|
|
93
105
|
private readonly abortController;
|
|
106
|
+
private readonly inputs;
|
|
94
107
|
lastJump: number;
|
|
108
|
+
readonly abortSignal: AbortSignal;
|
|
95
109
|
constructor(camera: Object3D, world: BvhPhysicsWorld, domElement: HTMLElement, options?: SimpleCharacterOptions);
|
|
96
110
|
private init;
|
|
97
111
|
update(delta: number): void;
|
|
@@ -99,3 +113,4 @@ export declare class SimpleCharacter extends Group<Object3DEventMap & {
|
|
|
99
113
|
}
|
|
100
114
|
export * from './update-input-velocity.js';
|
|
101
115
|
export * from './update-rotation.js';
|
|
116
|
+
export * from './apply-input-options.js';
|
|
@@ -2,7 +2,7 @@ import { VRM, VRMUtils } from '@pixiv/three-vrm';
|
|
|
2
2
|
import { runTimeline, GraphTimeline } from '@pmndrs/timeline';
|
|
3
3
|
import { Group, Vector3 } from 'three';
|
|
4
4
|
import { CharacterCameraBehavior } from '../camera.js';
|
|
5
|
-
import { LocomotionKeyboardInput, PointerCaptureInput, ScreenJoystickInput, ScreenJumpButtonInput,
|
|
5
|
+
import { LocomotionKeyboardInput, PointerCaptureInput, ScreenJoystickInput, ScreenJumpButtonInput, } from '../input/index.js';
|
|
6
6
|
import { loadCharacterModel, flattenCharacterModelOptions, } from '../model/index.js';
|
|
7
7
|
import { BvhCharacterPhysics } from '../physics/index.js';
|
|
8
8
|
import { loadSimpleCharacterJumpDownState } from './state/jump-down.js';
|
|
@@ -14,38 +14,31 @@ import { loadSimpleCharacterMovingState } from './state/movement.js';
|
|
|
14
14
|
import { updateSimpleCharacterInputVelocity } from './update-input-velocity.js';
|
|
15
15
|
import { updateSimpleCharacterRotation } from './update-rotation.js';
|
|
16
16
|
import { shouldJump } from '../utils.js';
|
|
17
|
+
import { applySimpleCharacterInputOptions } from './apply-input-options.js';
|
|
17
18
|
export class SimpleCharacter extends Group {
|
|
18
19
|
camera;
|
|
19
20
|
world;
|
|
20
21
|
options;
|
|
21
22
|
cameraBehavior;
|
|
22
23
|
physics;
|
|
23
|
-
inputSystem;
|
|
24
24
|
currentAnimationRef = {};
|
|
25
25
|
//loaded asychronously
|
|
26
26
|
model;
|
|
27
27
|
updateTimeline;
|
|
28
28
|
graph = new GraphTimeline('moving');
|
|
29
29
|
abortController = new AbortController();
|
|
30
|
+
inputs;
|
|
30
31
|
lastJump = 0;
|
|
32
|
+
abortSignal = this.abortController.signal;
|
|
31
33
|
constructor(camera, world, domElement, options = {}) {
|
|
32
34
|
super();
|
|
33
35
|
this.camera = camera;
|
|
34
36
|
this.world = world;
|
|
35
37
|
this.options = options;
|
|
36
|
-
this.
|
|
37
|
-
|
|
38
|
-
ScreenJoystickInput,
|
|
39
|
-
ScreenJumpButtonInput,
|
|
40
|
-
PointerCaptureInput,
|
|
41
|
-
LocomotionKeyboardInput,
|
|
42
|
-
];
|
|
43
|
-
for (let input of inputOptions) {
|
|
44
|
-
this.inputSystem.add(typeof input === 'function' ? new input(domElement) : input);
|
|
45
|
-
}
|
|
38
|
+
this.inputs = (options.input ?? [ScreenJoystickInput, ScreenJumpButtonInput, PointerCaptureInput, LocomotionKeyboardInput]).map((Input) => new Input(domElement));
|
|
39
|
+
applySimpleCharacterInputOptions(this.inputs, options.inputOptions);
|
|
46
40
|
// camera behavior
|
|
47
41
|
this.cameraBehavior = new CharacterCameraBehavior();
|
|
48
|
-
console.log(this.graph);
|
|
49
42
|
// physics
|
|
50
43
|
this.physics = new BvhCharacterPhysics(world);
|
|
51
44
|
// timeline graph
|
|
@@ -81,29 +74,31 @@ export class SimpleCharacter extends Group {
|
|
|
81
74
|
const jumpOptions = this.options.movement?.jump;
|
|
82
75
|
if (jumpOptions != false &&
|
|
83
76
|
this.model == null &&
|
|
84
|
-
shouldJump(this.physics, this.
|
|
77
|
+
shouldJump(this.physics, this.lastJump, jumpOptions == true ? undefined : jumpOptions?.bufferTime)) {
|
|
85
78
|
this.physics.applyVelocity(new Vector3(0, (typeof this.options.movement?.jump === 'object' ? this.options.movement?.jump.speed : undefined) ?? 8, 0));
|
|
86
79
|
this.lastJump = performance.now() / 1000;
|
|
87
80
|
}
|
|
88
81
|
if (this.model != null) {
|
|
89
82
|
updateSimpleCharacterRotation(delta, this.physics, this.camera, this.model, this.options.animation);
|
|
90
83
|
}
|
|
91
|
-
updateSimpleCharacterInputVelocity(this.camera, this.
|
|
84
|
+
updateSimpleCharacterInputVelocity(this.camera, this.physics, this.options.movement);
|
|
92
85
|
this.updateTimeline?.(undefined, delta);
|
|
93
86
|
this.model?.mixer.update(delta);
|
|
94
87
|
if (this.model instanceof VRM) {
|
|
95
88
|
this.model.update(delta);
|
|
96
89
|
}
|
|
97
90
|
this.physics.update(this, delta, this.options.physics);
|
|
98
|
-
this.cameraBehavior.update(this.camera, this,
|
|
91
|
+
this.cameraBehavior.update(this.camera, this, delta, this.world.raycast.bind(this.world), this.options.cameraBehavior);
|
|
99
92
|
}
|
|
100
93
|
dispose() {
|
|
101
94
|
this.abortController.abort();
|
|
102
95
|
this.parent?.remove(this);
|
|
103
96
|
this.model?.scene.dispatchEvent({ type: 'dispose' });
|
|
104
|
-
this.
|
|
97
|
+
this.inputs.forEach((input) => input.dispose());
|
|
98
|
+
this.cameraBehavior.dispose();
|
|
105
99
|
VRMUtils.deepDispose(this);
|
|
106
100
|
}
|
|
107
101
|
}
|
|
108
102
|
export * from './update-input-velocity.js';
|
|
109
103
|
export * from './update-rotation.js';
|
|
104
|
+
export * from './apply-input-options.js';
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { action, timePassed } from '@pmndrs/timeline';
|
|
2
2
|
import { LoopOnce } from 'three';
|
|
3
|
+
import { JumpDownAnimationUrl } from '../../animation/default.js';
|
|
3
4
|
import { flattenCharacterAnimationOptions, loadCharacterAnimation } from '../../animation/index.js';
|
|
4
5
|
import { startAnimation } from '../../utils.js';
|
|
5
6
|
import { DefaultCrossFadeDuration } from '../defaults.js';
|
|
@@ -8,7 +9,7 @@ export async function loadSimpleCharacterJumpDownState(state, options) {
|
|
|
8
9
|
if (model == null) {
|
|
9
10
|
throw new Error(`Unable to load animation without existing model`);
|
|
10
11
|
}
|
|
11
|
-
const jumpDown = model.mixer.clipAction(await loadCharacterAnimation(model, ...flattenCharacterAnimationOptions(
|
|
12
|
+
const jumpDown = model.mixer.clipAction(await loadCharacterAnimation(model, ...flattenCharacterAnimationOptions({ url: JumpDownAnimationUrl, ...options.animation?.jumpDown })));
|
|
12
13
|
jumpDown.loop = LoopOnce;
|
|
13
14
|
jumpDown.clampWhenFinished = true;
|
|
14
15
|
return {
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { action, animationFinished } from '@pmndrs/timeline';
|
|
2
2
|
import { LoopOnce, Vector3 } from 'three';
|
|
3
|
+
import { JumpForwardAnimationUrl } from '../../animation/default.js';
|
|
3
4
|
import { flattenCharacterAnimationOptions, loadCharacterAnimation } from '../../animation/index.js';
|
|
4
5
|
import { startAnimation } from '../../utils.js';
|
|
5
6
|
import { DefaultCrossFadeDuration } from '../defaults.js';
|
|
@@ -8,9 +9,10 @@ export async function loadSimpleCharacterJumpForwardAction(state, options) {
|
|
|
8
9
|
if (model == null) {
|
|
9
10
|
throw new Error(`Unable to load animation without existing model`);
|
|
10
11
|
}
|
|
11
|
-
const jumpForward = model.mixer.clipAction(await loadCharacterAnimation(model, ...flattenCharacterAnimationOptions(
|
|
12
|
-
url:
|
|
12
|
+
const jumpForward = model.mixer.clipAction(await loadCharacterAnimation(model, ...flattenCharacterAnimationOptions({
|
|
13
|
+
url: JumpForwardAnimationUrl,
|
|
13
14
|
scaleTime: 0.9,
|
|
15
|
+
...options.animation?.jumpForward,
|
|
14
16
|
})));
|
|
15
17
|
jumpForward.loop = LoopOnce;
|
|
16
18
|
jumpForward.clampWhenFinished = true;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { action } from '@pmndrs/timeline';
|
|
2
|
+
import { JumpLoopAnimationUrl } from '../../animation/default.js';
|
|
2
3
|
import { flattenCharacterAnimationOptions, loadCharacterAnimation } from '../../animation/index.js';
|
|
3
4
|
import { startAnimation } from '../../utils.js';
|
|
4
5
|
import { DefaultCrossFadeDuration } from '../defaults.js';
|
|
@@ -7,7 +8,7 @@ export async function loadSimpleCharacterJumpLoopState(state, options) {
|
|
|
7
8
|
if (model == null) {
|
|
8
9
|
throw new Error(`Unable to load animation without existing model`);
|
|
9
10
|
}
|
|
10
|
-
const jumpLoop = model.mixer.clipAction(await loadCharacterAnimation(model, ...flattenCharacterAnimationOptions(
|
|
11
|
+
const jumpLoop = model.mixer.clipAction(await loadCharacterAnimation(model, ...flattenCharacterAnimationOptions({ url: JumpLoopAnimationUrl, ...options.animation?.jumpLoop })));
|
|
11
12
|
return {
|
|
12
13
|
timeline: () => action({
|
|
13
14
|
init: () => {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { action, timePassed } from '@pmndrs/timeline';
|
|
2
|
-
import {
|
|
2
|
+
import { RunAction } from '../../input/index.js';
|
|
3
3
|
import { startAnimation } from '../../utils.js';
|
|
4
4
|
import { DefaultCrossFadeDuration, DefaultJumDelay } from '../defaults.js';
|
|
5
5
|
export async function loadSimpleCharacterJumpStartState(jumpUp, jumpForward, state, options) {
|
|
@@ -24,7 +24,7 @@ export async function loadSimpleCharacterJumpStartState(jumpUp, jumpForward, sta
|
|
|
24
24
|
}),
|
|
25
25
|
transitionTo: {
|
|
26
26
|
jumpDown: { whenUpdate: () => !state.physics.isGrounded },
|
|
27
|
-
finally: () => (
|
|
27
|
+
finally: () => (RunAction.get() ? 'jumpForward' : 'jumpUp'),
|
|
28
28
|
},
|
|
29
29
|
};
|
|
30
30
|
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { action, animationFinished } from '@pmndrs/timeline';
|
|
2
2
|
import { LoopOnce, Vector3 } from 'three';
|
|
3
|
+
import { JumpUpAnimationUrl } from '../../animation/default.js';
|
|
3
4
|
import { flattenCharacterAnimationOptions, loadCharacterAnimation } from '../../animation/index.js';
|
|
4
5
|
import { startAnimation } from '../../utils.js';
|
|
5
6
|
export async function loadSimpleCharacterJumpUpAction(state, options) {
|
|
@@ -7,8 +8,9 @@ export async function loadSimpleCharacterJumpUpAction(state, options) {
|
|
|
7
8
|
if (model == null) {
|
|
8
9
|
throw new Error(`Unable to load animation without existing model`);
|
|
9
10
|
}
|
|
10
|
-
const jumpUp = model.mixer.clipAction(await loadCharacterAnimation(model, ...flattenCharacterAnimationOptions(
|
|
11
|
-
url:
|
|
11
|
+
const jumpUp = model.mixer.clipAction(await loadCharacterAnimation(model, ...flattenCharacterAnimationOptions({
|
|
12
|
+
url: JumpUpAnimationUrl,
|
|
13
|
+
...options.animation?.jumpUp,
|
|
12
14
|
})));
|
|
13
15
|
jumpUp.loop = LoopOnce;
|
|
14
16
|
jumpUp.clampWhenFinished = true;
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { action } from '@pmndrs/timeline';
|
|
2
|
+
import { IdleAnimationUrl, RunAnimationUrl, WalkAnimationUrl } from '../../animation/default.js';
|
|
2
3
|
import { flattenCharacterAnimationOptions, loadCharacterAnimation } from '../../animation/index.js';
|
|
3
|
-
import {
|
|
4
|
+
import { RunAction } from '../../input/index.js';
|
|
4
5
|
import { shouldJump, startAnimation } from '../../utils.js';
|
|
5
6
|
import { DefaultCrossFadeDuration } from '../defaults.js';
|
|
6
7
|
export async function loadSimpleCharacterMovingState(state, options) {
|
|
@@ -8,16 +9,19 @@ export async function loadSimpleCharacterMovingState(state, options) {
|
|
|
8
9
|
if (model == null) {
|
|
9
10
|
throw new Error(`Unable to load animation without existing model`);
|
|
10
11
|
}
|
|
11
|
-
const idle = model.mixer.clipAction(await loadCharacterAnimation(model, ...flattenCharacterAnimationOptions(
|
|
12
|
-
url:
|
|
12
|
+
const idle = model.mixer.clipAction(await loadCharacterAnimation(model, ...flattenCharacterAnimationOptions({
|
|
13
|
+
url: IdleAnimationUrl,
|
|
14
|
+
...options.animation?.idle,
|
|
13
15
|
})));
|
|
14
16
|
const run = model.mixer.clipAction(await loadCharacterAnimation(model, ...flattenCharacterAnimationOptions({
|
|
15
|
-
url:
|
|
17
|
+
url: RunAnimationUrl,
|
|
16
18
|
scaleTime: 0.8,
|
|
19
|
+
...options.animation?.run,
|
|
17
20
|
})));
|
|
18
|
-
const walk = model.mixer.clipAction(await loadCharacterAnimation(model, ...flattenCharacterAnimationOptions(
|
|
21
|
+
const walk = model.mixer.clipAction(await loadCharacterAnimation(model, ...flattenCharacterAnimationOptions({
|
|
19
22
|
scaleTime: 0.5,
|
|
20
|
-
url:
|
|
23
|
+
url: WalkAnimationUrl,
|
|
24
|
+
...options.animation?.walk,
|
|
21
25
|
})));
|
|
22
26
|
return {
|
|
23
27
|
timeline: () => {
|
|
@@ -28,7 +32,7 @@ export async function loadSimpleCharacterMovingState(state, options) {
|
|
|
28
32
|
if (state.physics.inputVelocity.lengthSq() === 0) {
|
|
29
33
|
nextAnimation = idle;
|
|
30
34
|
}
|
|
31
|
-
else if (
|
|
35
|
+
else if (RunAction.get() && options.movement?.run != false) {
|
|
32
36
|
nextAnimation = run;
|
|
33
37
|
}
|
|
34
38
|
else if (options.movement?.walk != false) {
|
|
@@ -51,7 +55,7 @@ export async function loadSimpleCharacterMovingState(state, options) {
|
|
|
51
55
|
transitionTo: {
|
|
52
56
|
jumpStart: {
|
|
53
57
|
whenUpdate: () => options.movement?.jump !== false &&
|
|
54
|
-
shouldJump(state.physics, state.
|
|
58
|
+
shouldJump(state.physics, state.lastJump, options.movement?.jump === true ? undefined : options.movement?.jump?.bufferTime),
|
|
55
59
|
},
|
|
56
60
|
jumpLoop: { whenUpdate: () => !state.physics.isGrounded },
|
|
57
61
|
},
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { Object3D } from 'three';
|
|
2
|
-
import { InputSystem } from '../input/index.js';
|
|
3
2
|
import type { SimpleCharacterMovementOptions } from './index.js';
|
|
4
3
|
import type { BvhCharacterPhysics } from '../physics/index.js';
|
|
5
|
-
export declare function updateSimpleCharacterInputVelocity(camera: Object3D,
|
|
4
|
+
export declare function updateSimpleCharacterInputVelocity(camera: Object3D, physics: BvhCharacterPhysics, options?: SimpleCharacterMovementOptions): void;
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { Euler, Quaternion } from 'three';
|
|
2
|
-
import {
|
|
2
|
+
import { RunAction, MoveLeftAction, MoveRightAction, MoveForwardAction, MoveBackwardAction } from '../input/index.js';
|
|
3
3
|
const cameraEuler = new Euler();
|
|
4
4
|
const cameraRotation = new Quaternion();
|
|
5
|
-
export function updateSimpleCharacterInputVelocity(camera,
|
|
5
|
+
export function updateSimpleCharacterInputVelocity(camera, physics, options) {
|
|
6
6
|
cameraEuler.setFromQuaternion(camera.getWorldQuaternion(cameraRotation), 'YXZ');
|
|
7
7
|
cameraEuler.x = 0;
|
|
8
8
|
cameraEuler.z = 0;
|
|
9
9
|
let inputSpeed = 0;
|
|
10
10
|
let runOptions = options?.run ?? true;
|
|
11
|
-
if (
|
|
11
|
+
if (RunAction.get() && runOptions !== false) {
|
|
12
12
|
runOptions = runOptions === true ? {} : runOptions;
|
|
13
13
|
inputSpeed = runOptions.speed ?? 6;
|
|
14
14
|
}
|
|
@@ -18,7 +18,7 @@ export function updateSimpleCharacterInputVelocity(camera, inputSystem, physics,
|
|
|
18
18
|
inputSpeed = walkOptions.speed ?? 3;
|
|
19
19
|
}
|
|
20
20
|
physics.inputVelocity
|
|
21
|
-
.set(-
|
|
21
|
+
.set(-MoveLeftAction.get() + MoveRightAction.get(), 0, -MoveForwardAction.get() + MoveBackwardAction.get())
|
|
22
22
|
.normalize()
|
|
23
23
|
.applyEuler(cameraEuler)
|
|
24
24
|
.multiplyScalar(inputSpeed);
|
package/dist/utils.d.ts
CHANGED
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { type InputSystem } from './input/index.js';
|
|
2
|
-
import type { CharacterAnimationMask } from './animation/index.js';
|
|
3
1
|
import type { CharacterModel } from './model/index.js';
|
|
4
2
|
import type { BvhCharacterPhysics } from './physics/index.js';
|
|
5
3
|
import type { AnimationAction } from 'three';
|
|
@@ -7,8 +5,10 @@ export declare function getIsMobileMediaQuery(): MediaQueryList | undefined;
|
|
|
7
5
|
export declare function isMobile(): boolean;
|
|
8
6
|
export type StartAnimationOptions = {
|
|
9
7
|
fadeDuration?: number;
|
|
8
|
+
sync?: boolean;
|
|
10
9
|
paused?: boolean;
|
|
11
|
-
|
|
10
|
+
crossFade?: boolean;
|
|
11
|
+
layer?: string;
|
|
12
12
|
};
|
|
13
|
-
export declare function startAnimation(animation: AnimationAction, currentAnimations: CharacterModel['currentAnimations'], { fadeDuration, paused,
|
|
14
|
-
export declare function shouldJump(physics: BvhCharacterPhysics,
|
|
13
|
+
export declare function startAnimation(animation: AnimationAction, currentAnimations: CharacterModel['currentAnimations'], { crossFade, layer, fadeDuration, paused, sync }: StartAnimationOptions): (() => void) | undefined;
|
|
14
|
+
export declare function shouldJump(physics: BvhCharacterPhysics, lastJump: number, bufferTime?: number): boolean;
|
package/dist/utils.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { JumpAction } from './input/index.js';
|
|
2
2
|
export function getIsMobileMediaQuery() {
|
|
3
3
|
if (typeof window === 'undefined' || typeof window.matchMedia !== 'function') {
|
|
4
4
|
return undefined;
|
|
@@ -8,24 +8,33 @@ export function getIsMobileMediaQuery() {
|
|
|
8
8
|
export function isMobile() {
|
|
9
9
|
return getIsMobileMediaQuery()?.matches ?? false;
|
|
10
10
|
}
|
|
11
|
-
export function startAnimation(animation, currentAnimations, { fadeDuration = 0.1, paused = false,
|
|
11
|
+
export function startAnimation(animation, currentAnimations, { crossFade = true, layer, fadeDuration = 0.1, paused = false, sync = false }) {
|
|
12
12
|
animation.reset();
|
|
13
13
|
animation.play();
|
|
14
14
|
animation.paused = paused;
|
|
15
|
-
|
|
15
|
+
if (!crossFade) {
|
|
16
|
+
animation.fadeIn(fadeDuration);
|
|
17
|
+
return () => {
|
|
18
|
+
animation.fadeOut(fadeDuration);
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
const currentAnimation = currentAnimations.get(layer);
|
|
22
|
+
if (currentAnimation != null && sync) {
|
|
23
|
+
animation.syncWith(currentAnimation);
|
|
24
|
+
}
|
|
16
25
|
if (currentAnimation != null) {
|
|
17
26
|
animation.crossFadeFrom(currentAnimation, fadeDuration);
|
|
18
27
|
}
|
|
19
28
|
else {
|
|
20
29
|
animation.fadeIn(fadeDuration);
|
|
21
30
|
}
|
|
22
|
-
currentAnimations.set(
|
|
31
|
+
currentAnimations.set(layer, animation);
|
|
23
32
|
}
|
|
24
|
-
export function shouldJump(physics,
|
|
33
|
+
export function shouldJump(physics, lastJump, bufferTime = 0.1) {
|
|
25
34
|
if (!physics.isGrounded) {
|
|
26
35
|
return false;
|
|
27
36
|
}
|
|
28
|
-
const lastTimePressed =
|
|
37
|
+
const lastTimePressed = JumpAction.getLatestTime();
|
|
29
38
|
if (lastTimePressed == null || lastJump > lastTimePressed) {
|
|
30
39
|
return false;
|
|
31
40
|
}
|
package/package.json
CHANGED
|
@@ -21,12 +21,12 @@
|
|
|
21
21
|
"peerDependencies": {
|
|
22
22
|
"three": "*"
|
|
23
23
|
},
|
|
24
|
-
"version": "0.2.
|
|
24
|
+
"version": "0.2.1",
|
|
25
25
|
"type": "module",
|
|
26
26
|
"dependencies": {
|
|
27
27
|
"@pixiv/three-vrm": "^3.4.2",
|
|
28
28
|
"@pixiv/three-vrm-animation": "^3.4.2",
|
|
29
|
-
"@pmndrs/timeline": "^0.3.
|
|
29
|
+
"@pmndrs/timeline": "^0.3.7",
|
|
30
30
|
"@viverse/sdk": "1.2.10-alpha.0",
|
|
31
31
|
"three-mesh-bvh": "^0.9.1"
|
|
32
32
|
},
|
package/dist/animation/bvh.d.ts
DELETED
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import { AnimationClip } from 'three';
|
|
2
|
-
import type { CharacterModel } from '../model/index.js';
|
|
3
|
-
import type { VRMHumanBoneName } from '@pixiv/three-vrm';
|
|
4
|
-
export declare function loadVrmModelBvhAnimations(model: CharacterModel, url: string, removeXZMovement: boolean, boneMap?: Record<string, VRMHumanBoneName>): Promise<Array<AnimationClip>>;
|
package/dist/animation/bvh.js
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { BVHLoader } from 'three/examples/jsm/Addons.js';
|
|
2
|
-
import { bvhBoneMap, fixModelAnimationClip } from './index.js';
|
|
3
|
-
const loader = new BVHLoader();
|
|
4
|
-
export async function loadVrmModelBvhAnimations(model, url, removeXZMovement, boneMap) {
|
|
5
|
-
const clipScene = await loader.loadAsync(url);
|
|
6
|
-
fixModelAnimationClip(model, clipScene.clip, undefined, removeXZMovement, boneMap ?? bvhBoneMap);
|
|
7
|
-
return [clipScene.clip];
|
|
8
|
-
}
|
package/dist/animation/fbx.d.ts
DELETED
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import { AnimationClip } from 'three';
|
|
2
|
-
import type { CharacterModel } from '../model/index.js';
|
|
3
|
-
import type { VRMHumanBoneName } from '@pixiv/three-vrm';
|
|
4
|
-
export declare function loadVrmModelFbxAnimations(model: CharacterModel, url: string, removeXZMovement: boolean, boneMap?: Record<string, VRMHumanBoneName>): Promise<Array<AnimationClip>>;
|
package/dist/animation/fbx.js
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { FBXLoader } from 'three/examples/jsm/Addons.js';
|
|
2
|
-
import { fixModelAnimationClip } from './index.js';
|
|
3
|
-
const loader = new FBXLoader();
|
|
4
|
-
export async function loadVrmModelFbxAnimations(model, url, removeXZMovement, boneMap) {
|
|
5
|
-
const clipScene = await loader.loadAsync(url);
|
|
6
|
-
clipScene.animations.forEach((clip) => fixModelAnimationClip(model, clip, clipScene, removeXZMovement, boneMap));
|
|
7
|
-
return clipScene.animations;
|
|
8
|
-
}
|
package/dist/animation/gltf.d.ts
DELETED
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
import { AnimationClip } from 'three';
|
|
2
|
-
import type { CharacterModel, VRMHumanBoneName } from '../model/index.js';
|
|
3
|
-
export declare function loadVrmModelGltfAnimations(model: CharacterModel, url: string, removeXZMovement: boolean, boneMap?: Record<string, VRMHumanBoneName>): Promise<Array<AnimationClip>>;
|
package/dist/animation/gltf.js
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { GLTFLoader } from 'three/examples/jsm/Addons.js';
|
|
2
|
-
import { fixModelAnimationClip } from './index.js';
|
|
3
|
-
const loader = new GLTFLoader();
|
|
4
|
-
export async function loadVrmModelGltfAnimations(model, url, removeXZMovement, boneMap) {
|
|
5
|
-
const { animations, scene: clipScene } = await loader.loadAsync(url);
|
|
6
|
-
animations.forEach((clip) => fixModelAnimationClip(model, clip, clipScene, removeXZMovement, boneMap));
|
|
7
|
-
return animations;
|
|
8
|
-
}
|
package/dist/animation/vrma.d.ts
DELETED
package/dist/animation/vrma.js
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
import { createVRMAnimationClip } from '@pixiv/three-vrm-animation';
|
|
2
|
-
import { vrmaLoader } from '../index.js';
|
|
3
|
-
export async function loadVrmModelVrmaAnimations(vrm, url, removeXZMovement) {
|
|
4
|
-
const animations = await vrmaLoader.loadAsync(url);
|
|
5
|
-
const vrmAnimations = animations.userData.vrmAnimations;
|
|
6
|
-
const clips = vrmAnimations.map((vrmAnimation) => createVRMAnimationClip(vrmAnimation, vrm));
|
|
7
|
-
return clips;
|
|
8
|
-
}
|