diff --git a/packages/frontend/src/pages/room.vue b/packages/frontend/src/pages/room.vue index 036ca99464..f8fea24b6f 100644 --- a/packages/frontend/src/pages/room.vue +++ b/packages/frontend/src/pages/room.vue @@ -94,6 +94,16 @@ SPDX-License-Identifier: AGPL-3.0-only 戻す 保存 + + + + reload @@ -130,6 +140,7 @@ function resize() { const isZenMode = ref(false); const isRoomSettingsOpen = ref(false); const isChanged = ref(false); +const graphicsQuality = ref<'low' | 'medium' | 'high'>('medium'); const data = localStorage.getItem('roomData') != null ? JSON.parse(localStorage.getItem('roomData')!) : { heya: { @@ -166,14 +177,14 @@ const data = localStorage.getItem('roomData') != null ? JSON.parse(localStorage. installedObjects: [], }; -console.log(data); - let latestData = deepClone(data); const controller = new RoomController(data); onMounted(async () => { - controller.init(canvas.value!); + controller.init(canvas.value!, { + graphicsQuality: graphicsQuality.value, + }); canvas.value!.focus(); @@ -299,6 +310,12 @@ async function revert() { isChanged.value = false; } +async function reload() { + await controller.reset(null, null, { + graphicsQuality: graphicsQuality.value, + }); +} + function expor() { const dataStr = 'data:text/json;charset=utf-8,' + encodeURIComponent(JSON.stringify(controller.roomState.value)); const dlAnchorElem = window.document.createElement('a'); diff --git a/packages/frontend/src/world/room/controller.ts b/packages/frontend/src/world/room/controller.ts index 8606b20b25..7d5cc194a5 100644 --- a/packages/frontend/src/world/room/controller.ts +++ b/packages/frontend/src/world/room/controller.ts @@ -13,11 +13,17 @@ import type { RoomState } from './engine.js'; import type { ObjectDef, RoomStateObject } from './object.js'; import * as sound from '@/utility/sound.js'; +type Options = { + workerMode?: boolean; + graphicsQuality?: 'low' | 'medium' | 'high'; +}; + // 抽象化レイヤー export class RoomController { private worker: Worker | null = null; private engine: RoomEngine | null = null; private canvas: HTMLCanvasElement | null = null; + private options: Options = {}; private isCanvasDragging = false; public isReady = ref(false); public isSitting = ref(false); @@ -44,21 +50,23 @@ export class RoomController { this.onCanvasClick = this.onCanvasClick.bind(this); } - public async init(canvas: HTMLCanvasElement, workerMode = false) { + public async init(canvas: HTMLCanvasElement, options: Options = {}) { this.canvas = canvas; this.canvas.width = canvas.clientWidth; this.canvas.height = canvas.clientHeight; + this.options = options; - if (workerMode) { + if (options.workerMode) { const offscreen = canvas.transferControlToOffscreen(); this.worker = new RoomWorker(); - this.worker.postMessage({ type: 'init', canvas: offscreen, roomState: this.roomState.value }, [offscreen]); + this.worker.postMessage({ type: 'init', canvas: offscreen, roomState: this.roomState.value, graphicsQuality: options.graphicsQuality }, [offscreen]); this.isReady.value = true; } else { const babylonEngine = new BABYLON.WebGPUEngine(canvas, { doNotHandleContextLost: true }); babylonEngine.compatibilityMode = false; await babylonEngine.initAsync(); - this.engine = new RoomEngine(this.roomState.value, { canvas, engine: babylonEngine }); + + this.engine = new RoomEngine(this.roomState.value, { canvas, engine: babylonEngine, graphicsQuality: options.graphicsQuality }); this.engine.on('loadingProgress', ({ progress }) => { this.initializeProgress.value = progress; }); @@ -163,16 +171,16 @@ export class RoomController { return false; } - public async reset(roomState: RoomState, canvas?: HTMLCanvasElement, workerMode = false) { + public async reset(roomState?: RoomState, canvas?: HTMLCanvasElement, options: Options = {}) { this.destroy(); - this.roomState.value = roomState; + if (roomState != null) this.roomState.value = roomState; this.isReady.value = false; this.isSitting.value = false; this.isEditMode.value = false; this.grabbing.value = null; this.selected.value = null; this.initializeProgress.value = 0; - await this.init(canvas ?? this.canvas!, workerMode); + await this.init(canvas ?? this.canvas!, options ?? this.options); } public pauseRender() { diff --git a/packages/frontend/src/world/room/engine.ts b/packages/frontend/src/world/room/engine.ts index 84882ce79a..e770557e40 100644 --- a/packages/frontend/src/world/room/engine.ts +++ b/packages/frontend/src/world/room/engine.ts @@ -26,7 +26,6 @@ import { deepClone } from '@/utility/clone.js'; const BAKE_TRANSFORM = false; // 実験的 const SNAPSHOT_RENDERING = true; // 実験的 const IGNORE_OBJECTS: string[] = []; // for debug -const USE_GLOW = true; // ドローコールが増えて重い const RENDER_OUTDOOR_ENV = false; const IN_WEB_WORKER = typeof window === 'undefined'; @@ -117,6 +116,7 @@ export type RoomEngineEvents = { }; export class RoomEngine extends EventEmitter { + private useGlow: boolean; private canvas: HTMLCanvasElement; private engine: BABYLON.WebGPUEngine; public scene: BABYLON.Scene; @@ -218,6 +218,7 @@ export class RoomEngine extends EventEmitter { constructor(roomState: RoomState, options: { canvas: HTMLCanvasElement; engine: BABYLON.WebGPUEngine; + graphicsQuality?: 'low' | 'medium' | 'high'; }) { super(); @@ -230,9 +231,13 @@ export class RoomEngine extends EventEmitter { }; this.canvas = options.canvas; + this.fps = options.graphicsQuality === 'low' || options.graphicsQuality === 'medium' ? 30 : null; + this.useGlow = options.graphicsQuality !== 'low'; + registerBuiltInLoaders(); this.engine = options.engine; + if (options.graphicsQuality === 'low') this.engine.setHardwareScalingLevel(2); this.scene = new BABYLON.Scene(this.engine); // なんかレンダリングがおかしくなるときがあるのでコメントアウト // オブジェクトを選択し、後ろを向いて別のオブジェクトを選択した後、最初のオブジェクトに振り返ると消えているなど @@ -350,7 +355,7 @@ export class RoomEngine extends EventEmitter { this.turnOnRoomLight(true); - if (USE_GLOW) { + if (this.useGlow) { this.gl = new BABYLON.GlowLayer('glow', this.scene, { //mainTextureFixedSize: 512, blurKernelSize: 64, @@ -407,7 +412,7 @@ export class RoomEngine extends EventEmitter { if (_DEV_) { // snapshot renderingかつglow layerが有効だとなんかクラッシュする - if (!(SNAPSHOT_RENDERING && USE_GLOW)) { + if (!(SNAPSHOT_RENDERING && this.useGlow)) { const axes = new AxesViewer(this.scene, 30); axes.xAxis.position = new BABYLON.Vector3(0, 30, 0); axes.yAxis.position = new BABYLON.Vector3(0, 30, 0);