diff --git a/packages/frontend/src/utility/room/objects/pictureFrame.ts b/packages/frontend/src/utility/room/objects/pictureFrame.ts index 6d01dc70d9..f3e37bddc7 100644 --- a/packages/frontend/src/utility/room/objects/pictureFrame.ts +++ b/packages/frontend/src/utility/room/objects/pictureFrame.ts @@ -5,6 +5,7 @@ import * as BABYLON from '@babylonjs/core'; import { defineObject } from '../engine.js'; +import { getPlaneUvIndexes } from '../utility.js'; export const pictureFrame = defineObject({ id: 'pictureFrame', @@ -87,21 +88,17 @@ export const pictureFrame = defineObject({ const pictureMaterial = findMaterial('__X_PICTURE__'); - const uvs = pictureMesh.getVerticesData(BABYLON.VertexBuffer.UVKind); + const uvs = pictureMesh.getVerticesData(BABYLON.VertexBuffer.UVKind)!; + const uvIndexes = getPlaneUvIndexes(pictureMesh); - /** - * a(x,y)---b(x,y) - * | | - * c(x,y)---d(x,y) - */ - 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 ax = uvs[uvIndexes[0]]; + const ay = uvs[uvIndexes[0] + 1]; + const bx = uvs[uvIndexes[1]]; + const by = uvs[uvIndexes[1] + 1]; + const cx = uvs[uvIndexes[2]]; + const cy = uvs[uvIndexes[2] + 1]; + const dx = uvs[uvIndexes[3]]; + const dy = uvs[uvIndexes[3] + 1]; const applyFit = () => { const tex = pictureMaterial.albedoTexture; @@ -124,49 +121,71 @@ export const pictureFrame = defineObject({ 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); + const ratio = targetAspect / srcAspect; + + let uRange: number; + let vRange: number; + + if (ratio < 1) { + uRange = ratio; // < 1 + vRange = 1; } 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); + uRange = 1; + vRange = 1 / ratio; // < 1 } + + const uMin = (1 - uRange) / 2; + const uMax = uMin + uRange; + const vMin = (1 - vRange) / 2; + const vMax = vMin + vRange; + + newAx = uMin; + newBx = uMax; + newCx = uMin; + newDx = uMax; + + newAy = 1 - vMax; + newBy = 1 - vMax; + newCy = 1 - vMin; + newDy = 1 - vMin; } 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); + const ratio = targetAspect / srcAspect; + + let uRange: number; + let vRange: number; + + if (ratio > 1) { + uRange = ratio; // > 1 + vRange = 1; } 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); + uRange = 1; + vRange = 1 / ratio; // > 1 } - } else if (options.fit === 'stretch') { - // do nothing + + const uMin = (1 - uRange) / 2; + const uMax = uMin + uRange; + const vMin = (1 - vRange) / 2; + const vMax = vMin + vRange; + + newAx = uMin; + newBx = uMax; + newCx = uMin; + newDx = uMax; + + newAy = 1 - vMax; + newBy = 1 - vMax; + newCy = 1 - vMin; + newDy = 1 - vMin; } - uvs[6] = newAx; - uvs[7] = newAy; - uvs[2] = newBx; - uvs[3] = newBy; - uvs[4] = newCx; - uvs[5] = newCy; - uvs[0] = newDx; - uvs[1] = newDy; + uvs[uvIndexes[0]] = newAx; + uvs[uvIndexes[0] + 1] = newAy; + uvs[uvIndexes[1]] = newBx; + uvs[uvIndexes[1] + 1] = newBy; + uvs[uvIndexes[2]] = newCx; + uvs[uvIndexes[2] + 1] = newCy; + uvs[uvIndexes[3]] = newDx; + uvs[uvIndexes[3] + 1] = newDy; pictureMesh.updateVerticesData(BABYLON.VertexBuffer.UVKind, uvs); }; diff --git a/packages/frontend/src/utility/room/objects/poster.ts b/packages/frontend/src/utility/room/objects/poster.ts index 7682d0299c..876f09fdda 100644 --- a/packages/frontend/src/utility/room/objects/poster.ts +++ b/packages/frontend/src/utility/room/objects/poster.ts @@ -5,6 +5,7 @@ import * as BABYLON from '@babylonjs/core'; import { defineObject } from '../engine.js'; +import { getPlaneUvIndexes } from '../utility.js'; export const poster = defineObject({ id: 'poster', @@ -52,22 +53,17 @@ export const poster = defineObject({ const pinMeshes = findMeshes('__X_PIN__'); - const uvs = pictureMesh.getVerticesData(BABYLON.VertexBuffer.UVKind); + const uvs = pictureMesh.getVerticesData(BABYLON.VertexBuffer.UVKind)!; + const uvIndexes = getPlaneUvIndexes(pictureMesh); - /** - * 0 1 - * 0 a(x,y) --- b(x,y) - * | | - * 1 c(x,y) --- d(x,y) - */ - const ax = uvs[4]; - const ay = uvs[5]; - const bx = uvs[6]; - const by = uvs[7]; - const cx = uvs[0]; - const cy = uvs[1]; - const dx = uvs[2]; - const dy = uvs[3]; + const ax = uvs[uvIndexes[0]]; + const ay = uvs[uvIndexes[0] + 1]; + const bx = uvs[uvIndexes[1]]; + const by = uvs[uvIndexes[1] + 1]; + const cx = uvs[uvIndexes[2]]; + const cy = uvs[uvIndexes[2] + 1]; + const dx = uvs[uvIndexes[3]]; + const dy = uvs[uvIndexes[3] + 1]; const applyFit = () => { const tex = pictureMaterial.albedoTexture; @@ -147,14 +143,14 @@ export const poster = defineObject({ newDy = 1 - vMin; } - uvs[4] = newAx; - uvs[5] = newAy; - uvs[6] = newBx; - uvs[7] = newBy; - uvs[0] = newCx; - uvs[1] = newCy; - uvs[2] = newDx; - uvs[3] = newDy; + uvs[uvIndexes[0]] = newAx; + uvs[uvIndexes[0] + 1] = newAy; + uvs[uvIndexes[1]] = newBx; + uvs[uvIndexes[1] + 1] = newBy; + uvs[uvIndexes[2]] = newCx; + uvs[uvIndexes[2] + 1] = newCy; + uvs[uvIndexes[3]] = newDx; + uvs[uvIndexes[3] + 1] = newDy; pictureMesh.updateVerticesData(BABYLON.VertexBuffer.UVKind, uvs); }; diff --git a/packages/frontend/src/utility/room/utility.ts b/packages/frontend/src/utility/room/utility.ts index ebe9445f06..2ebb16b4ca 100644 --- a/packages/frontend/src/utility/room/utility.ts +++ b/packages/frontend/src/utility/room/utility.ts @@ -292,6 +292,9 @@ export function initTv(room: RoomEngine, screenMesh: BABYLON.Mesh) { tvScreenMaterial.freeze(); } + const uvs = screenMesh.getVerticesData(BABYLON.VertexBuffer.UVKind)!; + const uvIndexes = getPlaneUvIndexes(screenMesh); + const applyTvTexture = (tlIndex: number) => { const [index, duration] = tvProgram.timeline[tlIndex]; @@ -311,15 +314,14 @@ export function initTv(room: RoomEngine, screenMesh: BABYLON.Mesh) { const dx = bx; const dy = cy; - const uvs = screenMesh.getVerticesData(BABYLON.VertexBuffer.UVKind); - uvs[0] = dx; - uvs[1] = dy; - uvs[2] = bx; - uvs[3] = by; - uvs[4] = cx; - uvs[5] = cy; - uvs[6] = ax; - uvs[7] = ay; + uvs[uvIndexes[0]] = ax; + uvs[uvIndexes[0] + 1] = ay; + uvs[uvIndexes[1]] = bx; + uvs[uvIndexes[1] + 1] = by; + uvs[uvIndexes[2]] = cx; + uvs[uvIndexes[2] + 1] = cy; + uvs[uvIndexes[3]] = dx; + uvs[uvIndexes[3] + 1] = dy; screenMesh.updateVerticesData(BABYLON.VertexBuffer.UVKind, uvs); const timeoutId = window.setTimeout(() => { @@ -331,3 +333,39 @@ export function initTv(room: RoomEngine, screenMesh: BABYLON.Mesh) { applyTvTexture(0); } + +/** + * 0 1 + * 0 a(x,y) --- b(x,y) + * | | + * 1 c(x,y) --- d(x,y) + */ +export function getPlaneUvIndexes(mesh: BABYLON.Mesh) { + const uvs = mesh.getVerticesData(BABYLON.VertexBuffer.UVKind); + if (uvs == null) { + throw new Error('Mesh does not have UV data'); + } + + let aIndex = 0; + let bIndex = 0; + let cIndex = 0; + let dIndex = 0; + + for (let i = 0; i < 8; i += 2) { + const x = uvs[i]; + const y = uvs[i + 1]; + + // 多少ずれがあってもいいように(例えばblenderではUV展開時にデフォルトでわずかなマージンを追加する)、中心より大きいか/小さいかで判定する + if (x < 0.5 && y < 0.5) { + aIndex = i; + } else if (x > 0.5 && y < 0.5) { + bIndex = i; + } else if (x < 0.5 && y > 0.5) { + cIndex = i; + } else if (x > 0.5 && y > 0.5) { + dIndex = i; + } + } + + return [aIndex, bIndex, cIndex, dIndex]; +}