Skip to content

Commit

Permalink
Merge branch 'AvatarClothing'
Browse files Browse the repository at this point in the history
  • Loading branch information
AdLer-Lukas committed Jan 22, 2025
2 parents 13cb855 + 22b8b9c commit 2d0cc8c
Show file tree
Hide file tree
Showing 3 changed files with 123 additions and 6 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
import AvatarEditorPreviewModelViewModel from "./AvatarEditorPreviewModelViewModel";
import { Mesh, Texture, TransformNode } from "@babylonjs/core";
import {
AnimationGroup,
Mesh,
Skeleton,
Texture,
TransformNode,
} from "@babylonjs/core";
import IScenePresenter from "../../../Babylon/SceneManagement/IScenePresenter";
import CoreDIContainer from "~DependencyInjection/CoreDIContainer";
import SCENE_TYPES, {
Expand All @@ -9,7 +15,10 @@ import AvatarEditorPreviewSceneDefinition from "../AvatarEditorPreviewSceneDefin
import {
AvatarBeardModels,
AvatarHairModels,
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 @@ -25,6 +34,12 @@ const baseModelLink = require("../../../../../../Assets/3dModels/sharedModels/av
export default class AvatarEditorPreviewModelView {
private scenePresenter: IScenePresenter;

private baseAnimatonGroups: AnimationGroup[];

private baseModelSkeleton: Skeleton;

private idleAnimationName: string = "ac_anim_idle2";

constructor(private viewModel: AvatarEditorPreviewModelViewModel) {
this.scenePresenter = CoreDIContainer.get<ScenePresenterFactory>(
SCENE_TYPES.ScenePresenterFactory,
Expand All @@ -38,16 +53,56 @@ 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.baseModelSkeleton = result.skeletons[0];

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

// Default-Meshes ausblenden
["defaultPants", "defaultShoes", "defaultTop"].forEach((meshName) => {
const meshToHide = this.viewModel.baseModelMeshes.find(
(m) => m.name === meshName,
);
if (meshToHide) {
meshToHide.setEnabled(false);
}
});

// find anchor nodes
this.viewModel.hairAnchorNode = result.transformNodes.find(
(node) => node.name === "anker_hair",
)!;
this.viewModel.beardAnchorNode = result.transformNodes.find(
(node) => node.name === "anker_beard",
)!;
this.viewModel.shirtAnchorNode = result.transformNodes.find(
(node) => node.name === "anker_top",
)!;
this.viewModel.pantsAnchorNode = result.transformNodes.find(
(node) => node.name === "anker_pants",
)!;
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.updateModelShirt("shirts-sweatshirt");
}
if (mesh.name === "defaultPants") {
mesh.dispose();
this.updateModelPants("pants-jeans");
}
if (mesh.name === "defaultShoes") {
mesh.dispose();
this.updateModelShoes("shoes-trainers");
}
});

await CoreDIContainer.get<ILoadAvatarConfigUseCase>(
USECASE_TYPES.ILoadAvatarConfigUseCase,
Expand All @@ -59,6 +114,9 @@ export default class AvatarEditorPreviewModelView {
this.updateEyes(this.viewModel.currentAvatarConfig.Value.eyes);
this.updateNose(this.viewModel.currentAvatarConfig.Value.nose);
this.updateMouth(this.viewModel.currentAvatarConfig.Value.mouth);
this.updateModelShirt(this.viewModel.currentAvatarConfig.Value.shirt);
this.updateModelPants(this.viewModel.currentAvatarConfig.Value.pants);
this.updateModelShoes(this.viewModel.currentAvatarConfig.Value.shoes);
}

private onAvatarConfigChanged(): void {
Expand All @@ -75,9 +133,16 @@ export default class AvatarEditorPreviewModelView {
this.updateNose(this.viewModel.avatarConfigDiff.Value.nose);
if (this.viewModel.avatarConfigDiff.Value.mouth !== undefined)
this.updateMouth(this.viewModel.avatarConfigDiff.Value.mouth);
if (this.viewModel.avatarConfigDiff.Value.shirt !== undefined)
this.updateModelShirt(this.viewModel.avatarConfigDiff.Value.shirt);
if (this.viewModel.avatarConfigDiff.Value.pants !== undefined)
this.updateModelPants(this.viewModel.avatarConfigDiff.Value.pants);
if (this.viewModel.avatarConfigDiff.Value.shoes !== undefined)
this.updateModelShoes(this.viewModel.avatarConfigDiff.Value.shoes);
}

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

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

private updateModelShirt(shirt?: AvatarShirtModels | undefined) {
this.updateModel(
shirt,
"clothing/shirts",
this.viewModel.shirtMeshes,
this.viewModel.shirtAnchorNode,
);
}

private updateModelPants(pants?: AvatarPantsModels | undefined) {
this.updateModel(
pants,
"clothing/pants",
this.viewModel.pantsMeshes,
this.viewModel.pantsAnchorNode,
);
}

private updateModelShoes(shirt?: AvatarShoesModels | undefined) {
this.updateModel(
shirt,
"clothing/shoes",
this.viewModel.shoesMeshes,
this.viewModel.shoesAnchorNode,
);
}

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 @@ -160,14 +257,23 @@ export default class AvatarEditorPreviewModelView {
`../../../../../../Assets/3dModels/sharedModels/avatar/${modelFolder}/aa-${newModel}.glb`,
),
);
result.meshes.forEach((mesh) => {
if (mesh instanceof Mesh) {
// Stelle sicher, dass es ein Mesh ist
mesh.skeleton = this.baseModelSkeleton;
}
});

modelMap.set(newModel, result.meshes as Mesh[]);
result.meshes[0].parent = anchorNode;
}

// 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 @@ -3,6 +3,9 @@ import AvatarConfigTO from "../../../../../Core/Application/DataTransferObjects/
import {
AvatarBeardModels,
AvatarHairModels,
AvatarPantsModels,
AvatarShoesModels,
AvatarShirtModels,
} from "../../../../../Core/Domain/AvatarModels/AvatarModelTypes";
import Observable from "../../../../../../Lib/Observable";

Expand All @@ -12,10 +15,16 @@ export default class AvatarEditorPreviewModelViewModel {
// anchor nodes
hairAnchorNode: TransformNode;
beardAnchorNode: TransformNode;
shirtAnchorNode: TransformNode;
pantsAnchorNode: TransformNode;
shoesAnchorNode: TransformNode;

// mesh maps
hairMeshes: Map<AvatarHairModels, Mesh[]> = new Map();
beardMeshes: Map<AvatarBeardModels, Mesh[]> = new Map();
shirtMeshes: Map<AvatarShirtModels, Mesh[]> = new Map();
pantsMeshes: Map<AvatarPantsModels, Mesh[]> = new Map();
shoesMeshes: Map<AvatarShoesModels, Mesh[]> = new Map();

currentAvatarConfig: Observable<AvatarConfigTO> =
new Observable<AvatarConfigTO>();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,5 +126,7 @@ export default class AvatarEditorPreviewSceneDefinition extends AbstractSceneDef
shadowGenerator.useBlurExponentialShadowMap = true;
shadowGenerator.blurScale = 10;
shadowGenerator.darkness = 0.6;

// this.scene.debugLayer.show();
}
}

0 comments on commit 2d0cc8c

Please sign in to comment.