From e7f313a1d6cf0bd737c7d6ff9c305b87e2ce0808 Mon Sep 17 00:00:00 2001 From: Giga Date: Mon, 4 Sep 2023 14:16:59 +1200 Subject: [PATCH] Update the local avatar's nametag position with the hip bone position Allows the nametag to move up/down along with animations. Related to #142. --- src/modules/entity/entities/NametagEntity.ts | 20 +++++++++++++++++--- src/modules/scene/vscene.ts | 5 +++-- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/src/modules/entity/entities/NametagEntity.ts b/src/modules/entity/entities/NametagEntity.ts index 813e65b0..f42d94e0 100644 --- a/src/modules/entity/entities/NametagEntity.ts +++ b/src/modules/entity/entities/NametagEntity.ts @@ -12,7 +12,7 @@ /* eslint-disable @typescript-eslint/no-magic-numbers */ /* eslint-disable new-cap */ -import { AbstractMesh, +import { type AbstractMesh, Color3, DynamicTexture, Matrix, @@ -25,6 +25,7 @@ import { AbstractMesh, import { DEFAULT_MESH_RENDER_GROUP_ID } from "@Modules/object"; import { Renderer } from "@Modules/scene"; import { userStore } from "@Stores/index"; +import { Hysteresis } from "@Modules/utility/hysteresis"; /** * Contains all of the memoized nametag meshes within the scene. @@ -119,7 +120,7 @@ export class NametagEntity { */ public static create( object: Mesh | AbstractMesh | TransformNode, - height: number, + height: number | (() => number), name: string, icon = false, color?: Color3, @@ -310,7 +311,15 @@ export class NametagEntity { // Position the nametag above the center of the object. const positionOffset = new Vector3(0, 0.15, 0); - mesh.position = new Vector3(positionOffset.x, height + positionOffset.y, positionOffset.z); + let h = 0; + let heightHysteresis: Nullable = null; + if (typeof height === "number") { + h = height + positionOffset.y; + } else { + h = height() + positionOffset.y; + heightHysteresis = new Hysteresis(() => height() + positionOffset.y, 100, positionOffset.y); + } + mesh.position = new Vector3(positionOffset.x, h, positionOffset.z); const scaleAdjustmentFactorX = object.scaling.x > 0 ? 1 / object.scaling.x : 1; const scaleAdjustmentFactorY = object.scaling.y > 0 ? 1 / object.scaling.y : 1; @@ -331,6 +340,11 @@ export class NametagEntity { if (!mesh) { return; } + // Update the nametag's position. + if (heightHysteresis) { + mesh.position.y = heightHysteresis.get(); + } + // Update the nametag's opacity. const avatar = Renderer.getScene()?.getMyAvatar(); if (avatar) { const avatarPosition = avatar.getAbsolutePosition().clone(); diff --git a/src/modules/scene/vscene.ts b/src/modules/scene/vscene.ts index dfdbe721..914ce850 100644 --- a/src/modules/scene/vscene.ts +++ b/src/modules/scene/vscene.ts @@ -323,7 +323,8 @@ export class VScene { } const avatarHeight = boundingVectors.max.y - boundingVectors.min.y; - const hipPosition = result.skeleton?.bones.find((bone) => bone.name === "Hips")?.position; + const hipBone = result.skeleton?.bones.find((bone) => bone.name === "Hips"); + const hipPosition = hipBone?.position; // Reload the avatar animations file in case the new avatar is a different size than the previous one. // The browser cache will prevent this from being fetched over the network if the avatar is switched frequently. @@ -380,7 +381,7 @@ export class VScene { let nametagColor = userStore.account.isAdmin ? Color3.FromHexString(applicationStore.theme.colors.primary) : undefined; NametagEntity.create( this._myAvatar, - avatarHeight, + () => (hipBone?.position.y ?? avatarHeight / 2) + avatarHeight / 2, userStore.avatar.displayName, false, nametagColor