diff --git a/.gitignore b/.gitignore index 7839e4de66..ed1daaf489 100644 --- a/.gitignore +++ b/.gitignore @@ -81,3 +81,6 @@ vite.config.local-dev.ts.timestamp-* # VSCode addon .favorites.json + +# Affinity +*.af~lock~ diff --git a/packages/frontend/assets/room/objects/tv/screen-uv.png b/packages/frontend/assets/room/objects/tv/screen-uv.png deleted file mode 100644 index 4bb74f031f..0000000000 Binary files a/packages/frontend/assets/room/objects/tv/screen-uv.png and /dev/null differ diff --git a/packages/frontend/assets/room/objects/tv/tv.blend b/packages/frontend/assets/room/objects/tv/tv.blend index 490e298e7b..cd86e041e1 100644 Binary files a/packages/frontend/assets/room/objects/tv/tv.blend and b/packages/frontend/assets/room/objects/tv/tv.blend differ diff --git a/packages/frontend/assets/room/objects/tv/tv.glb b/packages/frontend/assets/room/objects/tv/tv.glb index b9bd23896b..24b578043a 100644 Binary files a/packages/frontend/assets/room/objects/tv/tv.glb and b/packages/frontend/assets/room/objects/tv/tv.glb differ diff --git a/packages/frontend/assets/room/tv/shopping/shopping.af b/packages/frontend/assets/room/tv/shopping/shopping.af new file mode 100644 index 0000000000..043c3da60b Binary files /dev/null and b/packages/frontend/assets/room/tv/shopping/shopping.af differ diff --git a/packages/frontend/assets/room/tv/shopping/shopping.png b/packages/frontend/assets/room/tv/shopping/shopping.png new file mode 100644 index 0000000000..8e91a4cf0d Binary files /dev/null and b/packages/frontend/assets/room/tv/shopping/shopping.png differ diff --git a/packages/frontend/src/pages/room.vue b/packages/frontend/src/pages/room.vue index c7dfa480dc..bc61094b06 100644 --- a/packages/frontend/src/pages/room.vue +++ b/packages/frontend/src/pages/room.vue @@ -120,6 +120,11 @@ onMounted(() => { position: [-100, 70, 138], rotation: [0, 1.5, 0], sticky: 'c', + }, { + id: 'p', + type: 'tv', + position: [-115, 0, -85], + rotation: [0, 0, 0], }], }, { canvas: canvas.value!, diff --git a/packages/frontend/src/utility/room/engine.ts b/packages/frontend/src/utility/room/engine.ts index a02ebdb03a..ab98000ac2 100644 --- a/packages/frontend/src/utility/room/engine.ts +++ b/packages/frontend/src/utility/room/engine.ts @@ -420,10 +420,7 @@ export class RoomEngine { public async init() { await this.loadRoomModel(this.def.roomType); await this.loadEnvModel(); - - for (const objDef of this.def.objects) { - this.loadObject(objDef.id, objDef.type, new BABYLON.Vector3(...objDef.position), new BABYLON.Vector3(...objDef.rotation)); - } + await Promise.all(this.def.objects.map(o => this.loadObject(o.id, o.type, new BABYLON.Vector3(...o.position), new BABYLON.Vector3(...o.rotation)))); //const sphere = BABYLON.MeshBuilder.CreateSphere('sphere', { diameter: 1/*cm*/ }, this.scene); @@ -435,6 +432,58 @@ export class RoomEngine { } }, 10)); + // update tv texure + const tvProgramId = 'shopping'; + const tvProgram = TV_PROGRAMS[tvProgramId]; + const tvScreenMaterial = new BABYLON.StandardMaterial('tvScreenMaterial', this.scene); + tvScreenMaterial.diffuseColor = new BABYLON.Color3(0, 0, 0); + tvScreenMaterial.ambientColor = new BABYLON.Color3(0, 0, 0); + tvScreenMaterial.specularColor = new BABYLON.Color3(0, 0, 0); + tvScreenMaterial.emissiveTexture = new BABYLON.Texture(`/client-assets/room/tv/${tvProgramId}/${tvProgramId}.png`, this.scene, false, false); + tvScreenMaterial.emissiveTexture.level = 0.5; + tvScreenMaterial.emissiveColor = new BABYLON.Color3(0.2, 0.2, 0.2); + tvScreenMaterial.freeze(); + + const applyTvTexture = (tlIndex: number) => { + const [index, duration] = tvProgram.timeline[tlIndex]; + const tvIds = this.def.objects.entries().filter(([id, o]) => o.type === 'tv').map(([id, o]) => o.id); + + for (const tvId of tvIds) { + const tvMesh = this.objectMeshs.get(tvId); + const screenMesh = tvMesh?.getChildMeshes().find(m => m.name.startsWith('_TV_SCREEN_'))! as BABYLON.Mesh; + screenMesh.material = tvScreenMaterial; + + const aspect = 16 / 9; + + const x = index % tvProgram.textureColumns; + const y = Math.floor(index / tvProgram.textureColumns); + + const ax = x / tvProgram.textureColumns; + const ay = y / tvProgram.textureRows / aspect; + const bx = (x + 1) / tvProgram.textureColumns; + const by = ay; + const cx = ax; + const cy = (y + 1) / tvProgram.textureRows / aspect; + 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; + screenMesh.updateVerticesData(BABYLON.VertexBuffer.UVKind, uvs); + } + + window.setTimeout(() => applyTvTexture((tlIndex + 1) % tvProgram.timeline.length), duration); + }; + + applyTvTexture(0); + this.engine.runRenderLoop(() => { this.scene.render(); }); @@ -603,7 +652,13 @@ export class RoomEngine { obj.meshes[0].position = position; obj.meshes[0].rotation = rotation; - for (const mesh of obj.meshes) { + for (const m of obj.meshes) { + const mesh = m; + + if (mesh.name.startsWith('_TV_SCREEN_')) { + mesh.markVerticesDataAsUpdatable(BABYLON.VertexBuffer.UVKind, true); + } + mesh.metadata = { isObject: true, objectId: id, objectType: type }; mesh.checkCollisions = true; //if (mesh.name === '__root__') continue; @@ -689,3 +744,40 @@ export class RoomEngine { this.engine.dispose(); } } + +const TV_PROGRAMS = { + shopping: { + textureColumns: 8, + textureRows: 8, + timeline: [ + [0, 500], + [1, 500], + [0, 500], + [1, 500], + [0, 500], + [1, 500], + [2, 500], + [3, 500], + [2, 500], + [3, 500], + [4, 500], + [5, 500], + [4, 500], + [5, 500], + [6, 500], + [7, 500], + [8, 500], + [9, 500], + [8, 500], + [9, 500], + [2, 500], + [3, 500], + [2, 500], + [3, 500], + ], + }, +} satisfies Record;