mirror of
https://github.com/misskey-dev/misskey.git
synced 2026-03-21 11:40:49 +00:00
wip
This commit is contained in:
BIN
packages/frontend/assets/room/objects/poster/poster.blend
Normal file
BIN
packages/frontend/assets/room/objects/poster/poster.blend
Normal file
Binary file not shown.
BIN
packages/frontend/assets/room/objects/poster/poster.glb
Normal file
BIN
packages/frontend/assets/room/objects/poster/poster.glb
Normal file
Binary file not shown.
@@ -134,6 +134,7 @@ type ObjectDef<OpSc extends OptionsSchema = OptionsSchema> = {
|
||||
loaderResult: BABYLON.ISceneLoaderAsyncResult;
|
||||
meshUpdated: () => void;
|
||||
findMesh: (keyword: string) => BABYLON.Mesh;
|
||||
findMeshes: (keyword: string) => BABYLON.Mesh[];
|
||||
findMaterial: (keyword: string) => BABYLON.PBRMaterial;
|
||||
}) => RoomObjectInstance<GetOptionsSchemaValues<OpSc>>;
|
||||
};
|
||||
@@ -911,6 +912,10 @@ export class RoomEngine {
|
||||
}
|
||||
return mesh as BABYLON.Mesh;
|
||||
},
|
||||
findMeshes: (keyword) => {
|
||||
const meshes = root.getChildMeshes().filter(m => m.name.includes(keyword));
|
||||
return meshes as BABYLON.Mesh[];
|
||||
},
|
||||
findMaterial: (keyword) => {
|
||||
for (const m of root.getChildMeshes()) {
|
||||
if (m.material == null) continue;
|
||||
|
||||
@@ -43,6 +43,7 @@ import { petBottle } from './objects/petBottle.js';
|
||||
import { pictureFrame } from './objects/pictureFrame.js';
|
||||
import { plant } from './objects/plant.js';
|
||||
import { plant2 } from './objects/plant2.js';
|
||||
import { poster } from './objects/poster.js';
|
||||
import { powerStrip } from './objects/powerStrip.js';
|
||||
import { rolledUpPoster } from './objects/rolledUpPoster.js';
|
||||
import { roundRug } from './objects/roundRug.js';
|
||||
@@ -98,6 +99,7 @@ export const OBJECT_DEFS = [
|
||||
pictureFrame,
|
||||
plant,
|
||||
plant2,
|
||||
poster,
|
||||
powerStrip,
|
||||
rolledUpPoster,
|
||||
roundRug,
|
||||
|
||||
@@ -8,7 +8,7 @@ import { defineObject } from '../engine.js';
|
||||
|
||||
export const pictureFrame = defineObject({
|
||||
id: 'pictureFrame',
|
||||
name: 'Rectangular picture frame',
|
||||
name: 'Simple picture frame',
|
||||
options: {
|
||||
schema: {
|
||||
frameColor: {
|
||||
@@ -103,11 +103,10 @@ export const pictureFrame = defineObject({
|
||||
|
||||
const srcWidth = tex.getSize().width;
|
||||
const srcHeight = tex.getSize().height;
|
||||
const srcAspect = srcWidth / srcHeight;
|
||||
const targetWidth = options.width * (1 - (options.matHThickness * MAT_THICKNESS_FACTOR));
|
||||
const targetHeight = options.height * (1 - (options.matVThickness * MAT_THICKNESS_FACTOR));
|
||||
|
||||
const targetAspect = targetWidth / targetHeight;
|
||||
const srcAspect = srcWidth / srcHeight;
|
||||
|
||||
let newAx = ax;
|
||||
let newAy = ay;
|
||||
|
||||
189
packages/frontend/src/utility/room/objects/poster.ts
Normal file
189
packages/frontend/src/utility/room/objects/poster.ts
Normal file
@@ -0,0 +1,189 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: syuilo and misskey-project
|
||||
* SPDX-License-Identifier: AGPL-3.0-only
|
||||
*/
|
||||
|
||||
import * as BABYLON from '@babylonjs/core';
|
||||
import { defineObject } from '../engine.js';
|
||||
|
||||
export const poster = defineObject({
|
||||
id: 'poster',
|
||||
name: 'Poster',
|
||||
options: {
|
||||
schema: {
|
||||
width: {
|
||||
type: 'range',
|
||||
label: 'Width',
|
||||
min: 0,
|
||||
max: 1,
|
||||
step: 0.01,
|
||||
},
|
||||
height: {
|
||||
type: 'range',
|
||||
label: 'Height',
|
||||
min: 0,
|
||||
max: 1,
|
||||
step: 0.01,
|
||||
},
|
||||
customPicture: {
|
||||
type: 'image',
|
||||
label: 'Custom picture',
|
||||
},
|
||||
fit: {
|
||||
type: 'enum',
|
||||
label: 'Custom picture fit',
|
||||
enum: ['cover', 'contain', 'stretch'],
|
||||
},
|
||||
},
|
||||
default: {
|
||||
width: 0.15,
|
||||
height: 0.15,
|
||||
customPicture: null,
|
||||
fit: 'cover',
|
||||
},
|
||||
},
|
||||
placement: 'side',
|
||||
createInstance: ({ room, root, options, findMaterial, findMesh, findMeshes, meshUpdated }) => {
|
||||
const pictureMesh = findMesh('__X_PICTURE__');
|
||||
pictureMesh.rotationQuaternion = null;
|
||||
pictureMesh.markVerticesDataAsUpdatable(BABYLON.VertexBuffer.UVKind, true);
|
||||
|
||||
const pictureMaterial = findMaterial('__X_PICTURE__');
|
||||
|
||||
const pinMeshes = findMeshes('__X_PIN__');
|
||||
|
||||
const uvs = pictureMesh.getVerticesData(BABYLON.VertexBuffer.UVKind);
|
||||
const ax = uvs[6];
|
||||
const ay = uvs[7];
|
||||
const bx = uvs[2];
|
||||
const by = uvs[3];
|
||||
const cx = uvs[4];
|
||||
const cy = uvs[5];
|
||||
const dx = uvs[0];
|
||||
const dy = uvs[1];
|
||||
|
||||
const applyFit = () => {
|
||||
const tex = pictureMaterial.albedoTexture;
|
||||
if (tex == null) return;
|
||||
|
||||
const srcWidth = tex.getSize().width;
|
||||
const srcHeight = tex.getSize().height;
|
||||
const srcAspect = srcWidth / srcHeight;
|
||||
const targetWidth = options.width;
|
||||
const targetHeight = options.height;
|
||||
const targetAspect = targetWidth / targetHeight;
|
||||
|
||||
let newAx = ax;
|
||||
let newAy = ay;
|
||||
let newBx = bx;
|
||||
let newBy = by;
|
||||
let newCx = cx;
|
||||
let newCy = cy;
|
||||
let newDx = dx;
|
||||
let newDy = dy;
|
||||
|
||||
if (options.fit === 'cover') {
|
||||
if (targetAspect > srcAspect) {
|
||||
const fitHeight = targetWidth / srcAspect;
|
||||
const crop = (fitHeight - targetHeight) / fitHeight / 2;
|
||||
newAy = ay + crop * (by - ay);
|
||||
newBy = by - crop * (by - ay);
|
||||
newCy = cy + crop * (dy - cy);
|
||||
newDy = dy - crop * (dy - cy);
|
||||
} else {
|
||||
const fitWidth = targetHeight * srcAspect;
|
||||
const crop = (fitWidth - targetWidth) / fitWidth / 2;
|
||||
newAx = ax + crop * (bx - ax);
|
||||
newBx = bx - crop * (bx - ax);
|
||||
newCx = cx + crop * (dx - cx);
|
||||
newDx = dx - crop * (dx - cx);
|
||||
}
|
||||
} else if (options.fit === 'contain') {
|
||||
if (targetAspect > srcAspect) {
|
||||
const fitWidth = targetHeight * srcAspect;
|
||||
const crop = (fitWidth - targetWidth) / fitWidth / 2;
|
||||
newAx = ax + crop * (bx - ax);
|
||||
newBx = bx - crop * (bx - ax);
|
||||
newCx = cx + crop * (dx - cx);
|
||||
newDx = dx - crop * (dx - cx);
|
||||
} else {
|
||||
const fitHeight = targetWidth / srcAspect;
|
||||
const crop = (fitHeight - targetHeight) / fitHeight / 2;
|
||||
newAy = ay + crop * (by - ay);
|
||||
newBy = by - crop * (by - ay);
|
||||
newCy = cy + crop * (dy - cy);
|
||||
newDy = dy - crop * (dy - cy);
|
||||
}
|
||||
} else if (options.fit === 'stretch') {
|
||||
// do nothing
|
||||
}
|
||||
|
||||
uvs[6] = newAx;
|
||||
uvs[7] = newAy;
|
||||
uvs[2] = newBx;
|
||||
uvs[3] = newBy;
|
||||
uvs[4] = newCx;
|
||||
uvs[5] = newCy;
|
||||
uvs[0] = newDx;
|
||||
uvs[1] = newDy;
|
||||
|
||||
pictureMesh.updateVerticesData(BABYLON.VertexBuffer.UVKind, uvs);
|
||||
};
|
||||
|
||||
applyFit();
|
||||
|
||||
const applySize = () => {
|
||||
pictureMesh.morphTargetManager!.getTargetByName('Width')!.influence = options.width;
|
||||
pictureMesh.morphTargetManager!.getTargetByName('Height')!.influence = options.height;
|
||||
for (const pinMesh of pinMeshes) {
|
||||
pinMesh.morphTargetManager!.getTargetByName('Width')!.influence = options.width;
|
||||
pinMesh.morphTargetManager!.getTargetByName('Height')!.influence = options.height;
|
||||
}
|
||||
meshUpdated();
|
||||
|
||||
applyFit();
|
||||
};
|
||||
|
||||
applySize();
|
||||
|
||||
const applyCustomPicture = () => {
|
||||
if (options.customPicture != null) {
|
||||
const tex = new BABYLON.Texture(options.customPicture, room.scene, false, false);
|
||||
tex.wrapU = BABYLON.Texture.MIRROR_ADDRESSMODE;
|
||||
tex.wrapV = BABYLON.Texture.MIRROR_ADDRESSMODE;
|
||||
|
||||
pictureMaterial.albedoColor = new BABYLON.Color3(1, 1, 1);
|
||||
pictureMaterial.albedoTexture = tex;
|
||||
|
||||
applyFit();
|
||||
|
||||
tex.onLoadObservable.addOnce(() => {
|
||||
applyFit();
|
||||
});
|
||||
} else {
|
||||
pictureMaterial.albedoColor = new BABYLON.Color3(0.5, 0.5, 0.5);
|
||||
pictureMaterial.albedoTexture = null;
|
||||
}
|
||||
};
|
||||
|
||||
applyCustomPicture();
|
||||
|
||||
return {
|
||||
onInited: () => {
|
||||
|
||||
},
|
||||
onOptionsUpdated: ([k, v]) => {
|
||||
if (k === 'width' || k === 'height') {
|
||||
applySize();
|
||||
}
|
||||
if (k === 'customPicture') {
|
||||
applyCustomPicture();
|
||||
}
|
||||
if (k === 'fit') {
|
||||
applyFit();
|
||||
}
|
||||
},
|
||||
interactions: {},
|
||||
};
|
||||
},
|
||||
});
|
||||
Reference in New Issue
Block a user