diff --git a/packages/frontend/assets/room/objects/random-books/random-books.blend b/packages/frontend/assets/room/objects/random-books/random-books.blend new file mode 100644 index 0000000000..523240e723 Binary files /dev/null and b/packages/frontend/assets/room/objects/random-books/random-books.blend differ diff --git a/packages/frontend/assets/room/objects/random-books/random-books.glb b/packages/frontend/assets/room/objects/random-books/random-books.glb new file mode 100644 index 0000000000..e3f54e88a4 Binary files /dev/null and b/packages/frontend/assets/room/objects/random-books/random-books.glb differ diff --git a/packages/frontend/assets/room/objects/random-books/template.png b/packages/frontend/assets/room/objects/random-books/template.png new file mode 100644 index 0000000000..cdc6e04779 Binary files /dev/null and b/packages/frontend/assets/room/objects/random-books/template.png differ diff --git a/packages/frontend/assets/room/objects/random-books/texture.af b/packages/frontend/assets/room/objects/random-books/texture.af new file mode 100644 index 0000000000..e67c3c76b8 Binary files /dev/null and b/packages/frontend/assets/room/objects/random-books/texture.af differ diff --git a/packages/frontend/assets/room/objects/random-books/texture.png b/packages/frontend/assets/room/objects/random-books/texture.png new file mode 100644 index 0000000000..e8cfed5320 Binary files /dev/null and b/packages/frontend/assets/room/objects/random-books/texture.png differ diff --git a/packages/frontend/src/utility/room/object-defs.ts b/packages/frontend/src/utility/room/object-defs.ts index a619c41f07..ade15b2564 100644 --- a/packages/frontend/src/utility/room/object-defs.ts +++ b/packages/frontend/src/utility/room/object-defs.ts @@ -54,6 +54,7 @@ import { plant2 } from './objects/plant2.js'; import { poster } from './objects/poster.js'; import { powerStrip } from './objects/powerStrip.js'; import { radiometer } from './objects/radiometer.js'; +import { randomBooks } from './objects/randomBooks.js'; import { rolledUpPoster } from './objects/rolledUpPoster.js'; import { roundRug } from './objects/roundRug.js'; import { router } from './objects/router.js'; @@ -124,6 +125,7 @@ export const OBJECT_DEFS = [ poster, powerStrip, radiometer, + randomBooks, rolledUpPoster, roundRug, router, diff --git a/packages/frontend/src/utility/room/objects/randomBooks.ts b/packages/frontend/src/utility/room/objects/randomBooks.ts new file mode 100644 index 0000000000..651928bd33 --- /dev/null +++ b/packages/frontend/src/utility/room/objects/randomBooks.ts @@ -0,0 +1,72 @@ +/* + * SPDX-FileCopyrightText: syuilo and misskey-project + * SPDX-License-Identifier: AGPL-3.0-only + */ +import * as BABYLON from '@babylonjs/core'; +import { defineObject, WORLD_SCALE } from '../engine.js'; + +const randomRange = (min: number, max: number) => Math.random() * (max - min) + min; + +const remap = (value: number, fromMin: number, fromMax: number, toMin: number, toMax: number) => { + return toMin + ((value - fromMin) / (fromMax - fromMin)) * (toMax - toMin); +}; + +export const randomBooks = defineObject({ + id: 'randomBooks', + name: 'randomBooks', + options: { + schema: { + }, + default: { + }, + }, + placement: 'top', + createInstance: ({ options, model }) => { + const bodyMesh = model.findMesh('__X_BODY__'); + + const count = 4; + + let accumulatedPos = 0; + + for (let i = 0; i < count; i++) { + const mesh = bodyMesh.clone(); + mesh.makeGeometryUnique(); + mesh.morphTargetManager = bodyMesh.morphTargetManager.clone(); + mesh.markVerticesDataAsUpdatable(BABYLON.VertexBuffer.UVKind, true); + + const index = Math.floor(Math.random() * 4); + const x = index % 8; + const y = Math.floor(index / 8); + + const uvs = mesh.getVerticesData(BABYLON.VertexBuffer.UVKind)!; + for (let uvi = 0; uvi < uvs.length; uvi += 2) { + const u = uvs[uvi]; + const v = uvs[uvi + 1]; + uvs[uvi] = (u / 8) + (x / 8); + uvs[uvi + 1] = (v / 8) + (y / 8); + } + mesh.updateVerticesData(BABYLON.VertexBuffer.UVKind, uvs); + + const width = randomRange(0.15, 0.25); + const height = randomRange(0.2, 0.3); + const thickness = randomRange(0, 0.1); + mesh.morphTargetManager!.getTargetByName('Width')!.influence = width; + mesh.morphTargetManager!.getTargetByName('Height')!.influence = height; + mesh.morphTargetManager!.getTargetByName('Thickness')!.influence = thickness; + const thicknessCm = 1 + remap(thickness, 0, 1, 0, 100); + mesh.position.x = (accumulatedPos) / WORLD_SCALE; + accumulatedPos += thicknessCm + 1; + } + + bodyMesh.isVisible = false; + + model.updated(); + + return { + onInited: () => { + + }, + interactions: {}, + }; + }, +});