Skip to content

Commit

Permalink
Feature/avatar animation cleanup (#113)
Browse files Browse the repository at this point in the history
* removes rogue console.log

* implements method to cleanup undesired properties from animation tracks

* adds optional dev argument to test base model without merging parts

* updates web-avatar-client example to use idle animation from MML repo

* updates web-avatar-client example assets

* cleans up skinned mesh children to fix the avatar animation

* Removed dev argument

---------

Co-authored-by: Marcus Longmuir <marcus@mpl.dev>
  • Loading branch information
TheCodeTherapy and MarcusLongmuir committed Feb 25, 2024
1 parent 2cd1b88 commit 6a3b4e0
Show file tree
Hide file tree
Showing 9 changed files with 40 additions and 11 deletions.
3 changes: 3 additions & 0 deletions example/assets/avatar/anims/idle.glb
Git LFS file not shown
3 changes: 3 additions & 0 deletions example/assets/avatar/parts/BaseballJersey_PlainBlack_01.glb
Git LFS file not shown
3 changes: 3 additions & 0 deletions example/assets/avatar/parts/FemaleBody.glb
Git LFS file not shown
2 changes: 1 addition & 1 deletion example/web-avatar-client/src/AvatarEditor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {
import React, { useCallback, useEffect, useState } from "react";
import { Group, Object3D } from "three";

import idleAnimationURL from "../../assets/avatar/anims/AS_Andor_Stand_Idle.glb";
import idleAnimationURL from "../../assets/avatar/anims/idle.glb";
import hdrURL from "../../assets/hdr/puresky_2k.hdr";

type BodyPartTypes = "fullBody" | "head" | "upperBody" | "lowerBody" | "feet";
Expand Down
4 changes: 2 additions & 2 deletions example/web-avatar-client/src/collection.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"fullBody": [
{
"name": "Full Body 1",
"asset": "/assets/avatar/parts/SK_Outfit_Body_Male.glb",
"asset": "/assets/avatar/parts/FemaleBody.glb",
"thumb": "/assets/avatar/thumbs/SK_Outfit_Body_Male.jpg"
}
],
Expand Down Expand Up @@ -36,7 +36,7 @@
},
{
"name": "Dude Upper Body 3",
"asset": "/assets/avatar/parts/SK_Outfit_Three_Flanel_Shirt_01.glb",
"asset": "/assets/avatar/parts/BaseballJersey_PlainBlack_01.glb",
"thumb": "/assets/avatar/thumbs/SK_Outfit_Three_Flanel_Shirt_01.jpg"
}
],
Expand Down
2 changes: 1 addition & 1 deletion example/web-avatar-client/src/mmlCharacterDescription.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
//

export const mmlCharacterDescription: string = `
<m-character src="/assets/avatar/parts/SK_Outfit_Body_Male.glb">
<m-character src="/assets/avatar/parts/FemaleBody.glb">
<m-model src="/assets/avatar/parts/SK_Outfit_Hat_02.glb"></m-model>
<m-model src="/assets/avatar/parts/SK_Outfit_Two_Long_Coat_with_Collared_Shirt_01.glb"></m-model>
<m-model src="/assets/avatar/parts/SK_Outfit_Three_Tight_Jeans_with_Chain_01.glb"></m-model>
Expand Down
4 changes: 2 additions & 2 deletions packages/3d-web-avatar/src/character/MMLCharacter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
Group,
MathUtils,
Matrix4,
Mesh,
MeshStandardMaterial,
Object3D,
Skeleton,
SkinnedMesh,
Expand Down Expand Up @@ -72,7 +72,6 @@ export class MMLCharacter {
): Promise<Object3D> {
const fullBodyAsset = await this.modelLoader.load(fullBodyURL);
const fullBodyGLTF = this.skeletonHelpers.cloneGLTF(fullBodyAsset as GLTF, "fullBody");

const assetPromises: Array<Promise<{ asset: GLTF; part: MMLCharacterDescriptionPart }>> =
bodyParts.map((part) => {
return new Promise((resolve) => {
Expand Down Expand Up @@ -154,6 +153,7 @@ export class MMLCharacter {
skinnedMeshClone.castShadow = true;
skinnedMeshClone.receiveShadow = true;
skinnedMeshClone.bind(this.sharedSkeleton!, this.sharedMatrixWorld!);
skinnedMeshClone.children = [];
this.skinnedMeshesParent?.add(skinnedMeshClone);
}
});
Expand Down
28 changes: 25 additions & 3 deletions packages/3d-web-standalone-avatar-editor/src/AvatarRenderer.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { ModelLoader } from "@mml-io/3d-web-avatar";
import { TimeManager, CameraManager, CollisionsManager } from "@mml-io/3d-web-client-core";
import {
AnimationClip,
AnimationMixer,
Bone,
LinearSRGBColorSpace,
LoadingManager,
LoopRepeat,
Expand All @@ -20,8 +22,6 @@ import { Mirror } from "./scene/Mirror";

export class AvatarRenderer {
private readonly camOffset: Vector3 = new Vector3(0, 1.2, 0);
private readonly floorSize: number = 50;
private readonly fogDistance: number = this.floorSize - this.floorSize * 0.1;

private width: number = 1;
private height: number = 1;
Expand All @@ -44,6 +44,8 @@ export class AvatarRenderer {
public cameraTargetOffset: { x?: number; y?: number; z?: number } = {};
public cameraTargetDistance: number = 0;

private cleanupNonRotationAnimTracks: boolean = true;

constructor(
private hdrURL: string,
private idleAnimationURL: string,
Expand Down Expand Up @@ -126,13 +128,33 @@ export class AvatarRenderer {
);
}

private cleanAnimationClips(skeletalMesh: Object3D, animationClip: AnimationClip): AnimationClip {
const availableBones = new Set<string>();
skeletalMesh.traverse((child) => {
const asBone = child as Bone;
if (asBone.isBone) {
availableBones.add(child.name);
}
});
animationClip.tracks = animationClip.tracks.filter((track) => {
const [trackName, trackProperty] = track.name.split(".");
const shouldAnimate =
availableBones.has(trackName) && trackProperty !== "position" && trackProperty !== "scale";
return shouldAnimate;
});
return animationClip;
}

public async animateCharacter(model: Object3D) {
this.mixer = new AnimationMixer(model);
if (this.animationAsset === null) {
this.animationAsset = await this.modelLoader.load(this.idleAnimationURL);
}
if (this.animationAsset && this.animationAsset.animations) {
const animationClip = this.animationAsset.animations[0];
const animationClip = this.cleanupNonRotationAnimTracks
? this.cleanAnimationClips(this.animationAsset.scene, this.animationAsset.animations[0])
: this.animationAsset.animations[0];

const animationAction = this.mixer.clipAction(animationClip);
animationAction.setLoop(LoopRepeat, Infinity);
animationAction.play();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,6 @@ export class ModelScreenshotter {
const size = new Vector3();
boundingBox.getSize(size);

console.log("boundingBox", boundingBox);

const camera = new PerspectiveCamera(50, width / height, 0.1, 1000);
positionCameraToFitBoundingBox(camera, boundingBox, size, padding, [0, 15, 30]);

Expand Down

0 comments on commit 6a3b4e0

Please sign in to comment.