Skip to content

Commit

Permalink
change: VRMAnimation LookAt is now local space quaternion instead of …
Browse files Browse the repository at this point in the history
…model space translation

See: vrm-c/vrm-specification#456

transfer quaternion to VRMLookAt yaw-pitch using VRMLookAtQuaternionProxy (does it look good?)
  • Loading branch information
0b5vr committed Nov 20, 2023
1 parent c11d6e9 commit 157840e
Show file tree
Hide file tree
Showing 9 changed files with 86 additions and 35 deletions.
12 changes: 5 additions & 7 deletions packages/three-vrm-animation/examples/dnd.html
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import GUI from 'three/addons/libs/lil-gui.module.min.js';
import { VRMLoaderPlugin, VRMUtils } from '@pixiv/three-vrm';
import { createVRMAnimationClip, VRMAnimationLoaderPlugin } from '@pixiv/three-vrm-animation';
import { createVRMAnimationClip, VRMAnimationLoaderPlugin, VRMLookAtQuaternionProxy } from '@pixiv/three-vrm-animation';

// renderer
const renderer = new THREE.WebGLRenderer();
Expand Down Expand Up @@ -107,12 +107,10 @@

}

// Add look at target
const lookAtTarget = new THREE.Object3D();
lookAtTarget.name = 'lookAtTarget';
vrm.scene.add( lookAtTarget );
vrm.lookAt.target = lookAtTarget;
vrm.lookAt.autoUpdate = false;
// Add look at quaternion proxy to the VRM; which is needed to play the look at animation
const lookAtQuatProxy = new VRMLookAtQuaternionProxy( vrm.lookAt );
lookAtQuatProxy.name = 'lookAtQuaternionProxy';
vrm.scene.add( lookAtQuatProxy );

// Disable frustum culling
vrm.scene.traverse( ( obj ) => {
Expand Down
11 changes: 5 additions & 6 deletions packages/three-vrm-animation/examples/loader-plugin.html
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
import { VRMLoaderPlugin, VRMUtils } from '@pixiv/three-vrm';
import { createVRMAnimationClip, VRMAnimationLoaderPlugin } from '@pixiv/three-vrm-animation';
import { createVRMAnimationClip, VRMAnimationLoaderPlugin, VRMLookAtQuaternionProxy } from '@pixiv/three-vrm-animation';

( async () => {

Expand Down Expand Up @@ -98,11 +98,10 @@

} );

// Add look at target to the VRM; which is needed to play the look at animation
const lookAtTarget = new THREE.Object3D();
lookAtTarget.name = 'lookAtTarget';
vrm.scene.add( lookAtTarget );
vrm.lookAt.target = lookAtTarget;
// Add look at quaternion proxy to the VRM; which is needed to play the look at animation
const lookAtQuatProxy = new VRMLookAtQuaternionProxy( vrm.lookAt );
lookAtQuatProxy.name = 'lookAtQuaternionProxy';
vrm.scene.add( lookAtQuatProxy );

// Add VRM to the scene
console.log( vrm );
Expand Down
Binary file modified packages/three-vrm-animation/examples/models/test.vrma
Binary file not shown.
2 changes: 1 addition & 1 deletion packages/three-vrm-animation/src/VRMAnimation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export class VRMAnimation {
preset: Map<VRMExpressionPresetName, THREE.NumberKeyframeTrack>;
custom: Map<string, THREE.NumberKeyframeTrack>;
};
public lookAtTrack: THREE.VectorKeyframeTrack | null;
public lookAtTrack: THREE.QuaternionKeyframeTrack | null;

public constructor() {
this.duration = 0.0;
Expand Down
6 changes: 2 additions & 4 deletions packages/three-vrm-animation/src/VRMAnimationLoaderPlugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,7 @@ export class VRMAnimationLoaderPlugin implements GLTFLoaderPlugin {
const worldMatrixMap = await this._createBoneWorldMatrixMap(gltf, defExtension);

const hipsNode = defExtension.humanoid?.humanBones['hips']?.node;
const hips = hipsNode != null
? (await gltf.parser.getDependency('node', hipsNode)) as THREE.Object3D
: null;
const hips = hipsNode != null ? ((await gltf.parser.getDependency('node', hipsNode)) as THREE.Object3D) : null;

const restHipsPosition = new THREE.Vector3();
if (restHipsPosition != null) {
Expand Down Expand Up @@ -244,7 +242,7 @@ export class VRMAnimationLoaderPlugin implements GLTFLoaderPlugin {

// lookAt
if (node === nodeMap.lookAtIndex) {
if (path === 'translation') {
if (path === 'rotation') {
result.lookAtTrack = origTrack;
} else {
throw new Error(`Invalid path "${path}"`);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export interface VRMAnimationLoaderPluginOptions {
/**
* Specify a desired frame rate in case if the animation need to be baked.
* Animation bake occurs when the lookAt target is not a direct child of the root.
*/
bakeFrameRate?: number;
}
39 changes: 39 additions & 0 deletions packages/three-vrm-animation/src/VRMLookAtQuaternionProxy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { VRMLookAt } from '@pixiv/three-vrm-core';
import * as THREE from 'three';

const RAD2DEG = 180 / Math.PI;

const _eulerA = /*@__PURE__*/ new THREE.Euler();

export class VRMLookAtQuaternionProxy extends THREE.Object3D {
public readonly vrmLookAt: VRMLookAt;
public override readonly type: string | 'VRMLookAtQuaternionProxy';

public constructor(lookAt: VRMLookAt) {
super();

this.vrmLookAt = lookAt;

this.type = 'VRMLookAtQuaternionProxy';

// See: https://github.com/mrdoob/three.js/blob/r158/src/core/Object3D.js#L65
const prevRotationOnChangeCallback = this.rotation._onChangeCallback;
this.rotation._onChange(() => {
prevRotationOnChangeCallback();
this._applyToLookAt();
});

const prevQuaternionOnChangeCallback = this.quaternion._onChangeCallback;
this.quaternion._onChange(() => {
prevQuaternionOnChangeCallback();
this._applyToLookAt();
});
}

private _applyToLookAt(): void {
_eulerA.setFromQuaternion(this.quaternion, VRMLookAt.EULER_ORDER);

this.vrmLookAt.yaw = RAD2DEG * _eulerA.y;
this.vrmLookAt.pitch = RAD2DEG * _eulerA.x;
}
}
43 changes: 26 additions & 17 deletions packages/three-vrm-animation/src/createVRMAnimationClip.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import type {
VRMHumanoid,
} from '@pixiv/three-vrm-core';
import type { VRMAnimation } from './VRMAnimation';
import { VRMLookAtQuaternionProxy } from './VRMLookAtQuaternionProxy';

export function createVRMAnimationHumanoidTracks(
vrmAnimation: VRMAnimation,
Expand Down Expand Up @@ -117,23 +118,31 @@ export function createVRMAnimationClip(vrmAnimation: VRMAnimation, vrm: VRMCore)
}

if (vrm.lookAt != null) {
const lookAtTarget = vrm.lookAt.target;

if (lookAtTarget == null) {
console.warn('`vrm.lookAt.target` of the given VRM is not defined. Skipping lookAt animation');
} else {
if (lookAtTarget.name === '') {
console.warn(
'`vrm.lookAt.target.name` of the given VRM is empty. Setting the name `lookAtTarget` automatically',
);
lookAtTarget.name = 'lookAtTarget';
}

const track = createVRMAnimationLookAtTrack(vrmAnimation, `${lookAtTarget.name}.position`);

if (track != null) {
tracks.push(track);
}
// search VRMLookAtQuaternionProxy
let proxy = vrm.scene.children.find((obj) => obj instanceof VRMLookAtQuaternionProxy);

if (proxy == null) {
// if not found, create a new one
console.warn(
'createVRMAnimationClip: VRMLookAtQuaternionProxy is not found. Creating a new one automatically. To suppress this warning, create a VRMLookAtQuaternionProxy manually',
);

proxy = new VRMLookAtQuaternionProxy(vrm.lookAt);
proxy.name = 'VRMLookAtQuaternionProxy';
vrm.scene.add(proxy);
} else if (proxy.name == null) {
// if found but name is not set, set the name automatically
console.warn(
'createVRMAnimationClip: VRMLookAtQuaternionProxy is found but its name is not set. Setting the name automatically. To suppress this warning, set the name manually',
);

proxy.name = 'VRMLookAtQuaternionProxy';
}

// create a track
const track = createVRMAnimationLookAtTrack(vrmAnimation, `${proxy.name}.quaternion`);
if (track != null) {
tracks.push(track);
}
}

Expand Down
1 change: 1 addition & 0 deletions packages/three-vrm-animation/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ export {
} from './createVRMAnimationClip';
export { VRMAnimation } from './VRMAnimation';
export { VRMAnimationLoaderPlugin } from './VRMAnimationLoaderPlugin';
export { VRMLookAtQuaternionProxy } from './VRMLookAtQuaternionProxy';

0 comments on commit 157840e

Please sign in to comment.