diff --git a/packages/frontend-misskey-world-engine/src/PlayerContainer.ts b/packages/frontend-misskey-world-engine/src/PlayerContainer.ts index ee59a3e864..6331a48dd4 100644 --- a/packages/frontend-misskey-world-engine/src/PlayerContainer.ts +++ b/packages/frontend-misskey-world-engine/src/PlayerContainer.ts @@ -7,7 +7,7 @@ import * as BABYLON from '@babylonjs/core/pure.js'; import { cm, WORLD_SCALE } from 'misskey-world/src/utility.js'; import { AccessoryContainer } from './avatars/AccessoryContainer.js'; import { getAccessoryDef } from './avatars/accessory-defs.js'; -import { Timer } from './utility.js'; +import { createTextMesh, Timer } from './utility.js'; import type { WorldAvatar } from 'misskey-world/src/types.js'; export type PlayerProfile = { @@ -75,6 +75,25 @@ export class PlayerContainer { this.subRootContainerForAnim.parent = this.root; this.subRoot = new BABYLON.TransformNode(`player:${this.id}:subRoot`, params.scene); this.subRoot.parent = this.subRootContainerForAnim; + + const usernameLabelTex = new BABYLON.Texture('/client-assets/world/chars-black.png', this.scene, false, false); + usernameLabelTex.level = 1; + const usernameLabelMaterial = new BABYLON.StandardMaterial('usernameLabelMaterial', this.scene); + usernameLabelMaterial.roughness = 1; + usernameLabelMaterial.diffuseColor = new BABYLON.Color3(1, 1, 1); + usernameLabelMaterial.diffuseTexture = usernameLabelTex; + usernameLabelMaterial.emissiveColor = new BABYLON.Color3(1, 1, 1); + usernameLabelMaterial.emissiveTexture = usernameLabelTex; + usernameLabelMaterial.disableLighting = true; + const usernameLabelMesh = createTextMesh(this.profile.user?.username ?? '(anonymous)', { + size: cm(5), + material: usernameLabelMaterial, + }); + usernameLabelMesh.parent = this.subRoot; + usernameLabelMesh.position.y = cm(50); + usernameLabelMesh.billboardMode = BABYLON.Mesh.BILLBOARDMODE_ALL; + this.scene.addMesh(usernameLabelMesh); + if (params.state) this.applyState(params.state, true); console.log('PlayerContainer created', this.id); diff --git a/packages/frontend-misskey-world-engine/src/utility.ts b/packages/frontend-misskey-world-engine/src/utility.ts index f79e276087..198b8fb2dd 100644 --- a/packages/frontend-misskey-world-engine/src/utility.ts +++ b/packages/frontend-misskey-world-engine/src/utility.ts @@ -303,6 +303,53 @@ const TEXT_TEXTURE_CHAR_WIDTH_MAP = { '+': 0.6, }; +export function createTextMesh(text: string, options: { + size: number; + material: BABYLON.StandardMaterial; +}) { + const meshes: BABYLON.Mesh[] = []; + + let totalWidth = 0; + for (let i = 0; i < text.length; i++) { + const char = text[i]; + //const charWidth = TEXT_TEXTURE_CHAR_WIDTH_MAP[char] ?? 1; + const charWidth = 1; + totalWidth += options.size * charWidth; + } + + let xPos = -totalWidth / 2; + for (let i = 0; i < text.length; i++) { + const char = text[i]; + const index = TEXT_TEXTURE_CHAR_MAP[char]; + //const charWidth = TEXT_TEXTURE_CHAR_WIDTH_MAP[char] ?? 1; + const charWidth = 1; + const x = index % TEXT_TEXTURE_CHAR_COLS; + const y = Math.floor(index / TEXT_TEXTURE_CHAR_COLS); + + const plane = BABYLON.MeshBuilder.CreatePlane('plane', { + //width: options.size * charWidth, + //height: options.size, + size: options.size, + sideOrientation: BABYLON.Mesh.DOUBLESIDE, + updatable: true, + }); + const uvs = plane.getVerticesData(BABYLON.VertexBuffer.UVKind); + uvs[0] = uvs[6] = x / TEXT_TEXTURE_CHAR_COLS; + uvs[1] = uvs[3] = (y + 1) / TEXT_TEXTURE_CHAR_ROWS; + uvs[2] = uvs[4] = (x + 1) / TEXT_TEXTURE_CHAR_COLS; + uvs[5] = uvs[7] = y / TEXT_TEXTURE_CHAR_ROWS; + plane.updateVerticesData(BABYLON.VertexBuffer.UVKind, uvs); + plane.material = options.material; + xPos += (options.size * charWidth); + plane.position = new BABYLON.Vector3(xPos - (options.size / 2), 0, 0); + meshes.push(plane); + } + + const merged = BABYLON.Mesh.MergeMeshes(meshes, true, false, undefined, false, false); + + return merged!; +} + export class RecyvlingText { public maxChars: number; public size: number; diff --git a/packages/frontend/assets/world/chars-black.png b/packages/frontend/assets/world/chars-black.png new file mode 100644 index 0000000000..b611e3b20a Binary files /dev/null and b/packages/frontend/assets/world/chars-black.png differ