Skip to content

Commit

Permalink
added fix for desynced shirt animations
Browse files Browse the repository at this point in the history
  • Loading branch information
mountler committed Jan 21, 2025
1 parent 0b76d9c commit 08bedf7
Show file tree
Hide file tree
Showing 2 changed files with 72 additions and 9 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import AvatarEditorPreviewModelViewModel from "./AvatarEditorPreviewModelViewModel";
import { Mesh, Texture, TransformNode } from "@babylonjs/core";
import { AnimationGroup, Mesh, Texture, TransformNode } from "@babylonjs/core";
import IScenePresenter from "../../../Babylon/SceneManagement/IScenePresenter";
import CoreDIContainer from "~DependencyInjection/CoreDIContainer";
import SCENE_TYPES, {
Expand All @@ -9,10 +9,10 @@ import AvatarEditorPreviewSceneDefinition from "../AvatarEditorPreviewSceneDefin
import {
AvatarBeardModels,
AvatarHairModels,
AvatarShirtModels,
AvatarPantsModels,
AvatarShoesModels,
AvatarNoneModel,
AvatarShirtModels,
} from "src/Components/Core/Domain/AvatarModels/AvatarModelTypes";
import ILoadAvatarConfigUseCase from "src/Components/Core/Application/UseCases/LoadAvatarConfig/ILoadAvatarConfigUseCase";
import USECASE_TYPES from "~DependencyInjection/UseCases/USECASE_TYPES";
Expand All @@ -28,6 +28,10 @@ const baseModelLink = require("../../../../../../Assets/3dModels/sharedModels/av
export default class AvatarEditorPreviewModelView {
private scenePresenter: IScenePresenter;

private baseAnimatonGroups: AnimationGroup[];

private idleAnimationName: string = "ac_anim_idle2";

constructor(private viewModel: AvatarEditorPreviewModelViewModel) {
this.scenePresenter = CoreDIContainer.get<ScenePresenterFactory>(
SCENE_TYPES.ScenePresenterFactory,
Expand All @@ -41,6 +45,8 @@ export default class AvatarEditorPreviewModelView {
async asyncSetup(): Promise<void> {
// load base model and position it
const result = await this.scenePresenter.loadGLTFModel(baseModelLink);
this.baseAnimatonGroups = result.animationGroups;

this.viewModel.baseModelMeshes = result.meshes as Mesh[];
this.viewModel.baseModelMeshes[0].position.y = -1;

Expand Down Expand Up @@ -70,6 +76,16 @@ export default class AvatarEditorPreviewModelView {
this.viewModel.shoesAnchorNode = result.transformNodes.find(
(node) => node.name === "anker_shoes",
)!;
this.viewModel.shirtAnchorNode = result.transformNodes.find(
(node) => node.name === "anker_top",
)!;

this.viewModel.baseModelMeshes.forEach((mesh) => {
if (mesh.name === "defaultTop") {
mesh.dispose();
this.updateShirt("shirts-sweatshirt");
}
});

await CoreDIContainer.get<ILoadAvatarConfigUseCase>(
USECASE_TYPES.ILoadAvatarConfigUseCase,
Expand Down Expand Up @@ -109,6 +125,7 @@ export default class AvatarEditorPreviewModelView {
}

private updateModelHair(hair?: AvatarHairModels | undefined) {
if (!hair) return;
this.updateModel(
hair,
"hair/hairstyle",
Expand All @@ -118,6 +135,7 @@ export default class AvatarEditorPreviewModelView {
}

private updateModelBeard(beard?: AvatarBeardModels | undefined) {
if (!beard) return;
this.updateModel(
beard,
"hair/beards",
Expand All @@ -126,6 +144,17 @@ export default class AvatarEditorPreviewModelView {
);
}

private async updateShirt(shirt?: AvatarShirtModels | undefined) {
if (!shirt) return;

await this.updateModel(
shirt,
"clothing/shirts",
this.viewModel.shirtMeshes,
this.viewModel.shirtAnchorNode,
);
}

private updateModelShirt(shirt?: AvatarShirtModels | undefined) {
this.updateModel(
shirt,
Expand Down Expand Up @@ -159,45 +188,49 @@ export default class AvatarEditorPreviewModelView {
}

private updateEyeBrows(eyebrow?: number) {
if (eyebrow === undefined || eyebrow === null) return;
let eyebrowMat = this.viewModel.baseModelMeshes.find((mesh) =>
mesh.material?.name.includes("Eyebrow_mat"),
)?.material!;

let texture = eyebrowMat.getActiveTextures()[0] as Texture;
const tmp = AvatarEyeBrowTexture[eyebrow!];
const tmp = AvatarEyeBrowTexture[eyebrow];
texture.uOffset = tmp.uOffset;
texture.vOffset = tmp.vOffset;
}

private updateEyes(eyes?: number) {
if (eyes === undefined || eyes === null) return;
let eyeMat = this.viewModel.baseModelMeshes.find((mesh) =>
mesh.material?.name.includes("Eyes_mat"),
)?.material!;

let texture = eyeMat.getActiveTextures()[0] as Texture;
const tmp = AvatarEyeTexture[eyes!];
const tmp = AvatarEyeTexture[eyes];
texture.uOffset = tmp.uOffset;
texture.vOffset = tmp.vOffset;
}

private updateNose(nose?: number) {
if (nose === undefined || nose === null) return;
let noseMat = this.viewModel.baseModelMeshes.find((mesh) =>
mesh.material?.name.includes("Nose_mat"),
)?.material!;

let texture = noseMat.getActiveTextures()[0] as Texture;
const tmp = AvatarNoseTexture[nose!];
const tmp = AvatarNoseTexture[nose];
texture.uOffset = tmp.uOffset;
texture.vOffset = tmp.vOffset;
}

private updateMouth(mouth?: number) {
if (mouth === undefined || mouth === null) return;
let mouthMat = this.viewModel.baseModelMeshes.find((mesh) =>
mesh.material?.name.includes("Mouth_mat"),
)?.material!;

let texture = mouthMat.getActiveTextures()[0] as Texture;
const tmp = AvatarMouthTexture[mouth!];
const tmp = AvatarMouthTexture[mouth];
texture.uOffset = tmp.uOffset;
texture.vOffset = tmp.vOffset;
}
Expand All @@ -217,20 +250,50 @@ export default class AvatarEditorPreviewModelView {
}

// load model if not already loaded
if (!modelMap.has(newModel)) {
//if (!modelMap.has(newModel))
{
const result = await this.scenePresenter.loadGLTFModel(
require(
`../../../../../../Assets/3dModels/sharedModels/avatar/${modelFolder}/aa-${newModel}.glb`,
),
);
modelMap.set(newModel, result.meshes as Mesh[]);
result.meshes[0].parent = anchorNode;

let idleAnim: AnimationGroup;
let syncFrame: number;
this.baseAnimatonGroups.forEach((animation) => {
if (animation.name.includes(this.idleAnimationName)) {
idleAnim = animation;
}
});

result.animationGroups.forEach((animation) => {
if (animation.name.includes(this.idleAnimationName)) {
idleAnim.pause();
syncFrame = idleAnim.getCurrentFrame();

idleAnim.restart();
animation.goToFrame(syncFrame);
}
});

console.log("BaseModel-Animations");
this.baseAnimatonGroups.forEach((animation) => {
console.log(animation.name, ", isPlaying: ", animation.isPlaying);
});
console.log("Current-animations");
result.animationGroups.forEach((animation) => {
console.log(animation.name, ", isPlaying: ", animation.isPlaying);
});
}

// set all meshes to invisible except the new model
modelMap.forEach((meshes, type) => {
const newIsVisible = type === newModel;
meshes.forEach((mesh) => (mesh.isVisible = newIsVisible));
meshes.forEach((mesh) => {
mesh.isVisible = newIsVisible;
});
});
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import {
AvatarBeardModels,
AvatarHairModels,
AvatarPantsModels,
AvatarShirtModels,
AvatarShoesModels,
AvatarShirtModels,
} from "../../../../../Core/Domain/AvatarModels/AvatarModelTypes";
import Observable from "../../../../../../Lib/Observable";

Expand Down

0 comments on commit 08bedf7

Please sign in to comment.