1
0
mirror of https://github.com/misskey-dev/misskey.git synced 2026-05-13 14:05:35 +02:00
This commit is contained in:
syuilo
2026-04-27 09:02:49 +09:00
parent 3a5532211b
commit 88e7303779
6 changed files with 68 additions and 27 deletions

View File

@@ -269,6 +269,7 @@ const roomControllerOptions = computed<RoomControllerOptions>(() => ({
fps: fps.value,
resolution: resolution.value,
useVirtualJoystick,
workerMode: false,
}));
const controller = new RoomController(data, roomControllerOptions.value);

View File

@@ -62,8 +62,23 @@ export class RoomController {
if (this.options.workerMode) {
const offscreen = canvas.transferControlToOffscreen();
this.worker = new RoomWorker();
this.worker.postMessage({ type: 'init', canvas: offscreen, roomState: this.roomState.value, ...this.options }, [offscreen]);
this.isReady.value = true;
this.worker.postMessage({ type: 'init', canvas: offscreen, roomState: this.roomState.value, options: this.options }, [offscreen]);
this.worker.onmessage = (event) => {
switch (event.data?.type) {
case 'progress': {
this.initializeProgress.value = event.data.progress;
break;
}
case 'inited': {
this.initializeProgress.value = 1;
this.isReady.value = true;
break;
}
default: {
console.warn('Unrecognized message from worker:', event.data?.type);
}
}
};
} else {
const babylonEngine = new BABYLON.WebGPUEngine(canvas, { doNotHandleContextLost: true });
babylonEngine.compatibilityMode = false;
@@ -104,6 +119,14 @@ export class RoomController {
this.engine.on('playSfxUrl', ({ url, options }) => {
sound.playUrl(url, options);
});
if (_DEV_) {
(window as any).showBabylonInspector = () => {
import('@babylonjs/inspector').then(({ ShowInspector }) => {
ShowInspector(this.engine.scene);
});
};
}
}
this.canvas.addEventListener('keydown', this.onCanvasKeydown);

View File

@@ -10,9 +10,7 @@
// TODO: テクスチャ置き換え時、元のテクスチャをちゃんとdispose
import * as BABYLON from '@babylonjs/core';
import { AxesViewer } from '@babylonjs/core/Debug/axesViewer';
import { registerBuiltInLoaders } from '@babylonjs/loaders/dynamic';
import { BoundingBoxRenderer } from '@babylonjs/core/Rendering/boundingBoxRenderer';
import { GridMaterial } from '@babylonjs/materials';
import { EventEmitter } from 'eventemitter3';
import { TIME_MAP, scaleMorph, camelToKebab, cm, WORLD_SCALE, getMeshesBoundingBox, Timer, getYRotationDirection, FreeCameraTouchVirtualJoystickInput } from '../utility.js';
@@ -437,18 +435,13 @@ export class RoomEngine extends EventEmitter<RoomEngineEvents> {
if (_DEV_) {
// snapshot renderingかつglow layerが有効だとなんかクラッシュする
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);
axes.zAxis.position = new BABYLON.Vector3(0, 30, 0);
}
if (!IN_WEB_WORKER) {
(window as any).showBabylonInspector = () => {
import('@babylonjs/inspector').then(({ ShowInspector }) => {
ShowInspector(this.scene);
});
};
import('@babylonjs/core/Debug/axesViewer').then(m => {
const { AxesViewer } = m;
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);
axes.zAxis.position = new BABYLON.Vector3(0, 30, 0);
});
}
}
}
@@ -588,7 +581,8 @@ export class RoomEngine extends EventEmitter<RoomEngineEvents> {
const renderLoop = (timeStamp: number) => {
if (this.disposed) return;
this.currentRafId = window.requestAnimationFrame(renderLoop);
// workerで実行される可能性がある
this.currentRafId = requestAnimationFrame(renderLoop);
const delta = timeStamp - then;
if (delta <= interval) return;
@@ -599,14 +593,16 @@ export class RoomEngine extends EventEmitter<RoomEngineEvents> {
this.engine.endFrame();
};
this.currentRafId = window.requestAnimationFrame(renderLoop);
// workerで実行される可能性がある
this.currentRafId = requestAnimationFrame(renderLoop);
}
}
public pauseRender() {
this.engine.stopRenderLoop();
if (this.currentRafId != null) {
window.cancelAnimationFrame(this.currentRafId);
// workerで実行される可能性がある
cancelAnimationFrame(this.currentRafId);
this.currentRafId = null;
}
}
@@ -1638,7 +1634,9 @@ export class RoomEngine extends EventEmitter<RoomEngineEvents> {
this.scene.customRenderTargets.push(reflectionProbe.cubeTexture);
reflectionProbe.cubeTexture.render();
await new Promise(res => window.setTimeout(res, 2000));
// workerで実行される可能性がある
// eslint-disable-next-line no-restricted-globals
await new Promise(res => setTimeout(res, 2000));
const tex = reflectionProbe.cubeTexture;
reflectionProbe.renderList = [];
@@ -1731,6 +1729,8 @@ export class RoomEngine extends EventEmitter<RoomEngineEvents> {
// ↑追記: engine.resizeした後に一瞬待つことで回避できることが判明
if (SNAPSHOT_RENDERING) this.sr.disableSnapshotRendering();
this.engine.resize();
// workerで実行される可能性がある
// eslint-disable-next-line no-restricted-globals
setTimeout(() => {
if (SNAPSHOT_RENDERING) this.sr.enableSnapshotRendering();
}, 1);
@@ -1738,7 +1738,8 @@ export class RoomEngine extends EventEmitter<RoomEngineEvents> {
public destroy() {
if (this.currentRafId != null) {
window.cancelAnimationFrame(this.currentRafId);
// workerで実行される可能性がある
cancelAnimationFrame(this.currentRafId);
this.currentRafId = null;
}
this.timer.dispose();

View File

@@ -5,7 +5,6 @@
import * as BABYLON from '@babylonjs/core';
import { applyMorphTargetsToMesh, cm, getPlaneUvIndexes, Timer } from '../utility.js';
import type { RoomEngine } from './engine.js';
export const SYSTEM_MESH_NAMES = ['__TOP__', '__SIDE__', '__PICK__', '__COLLISION__'];
export const SYSTEM_HEYA_MESH_NAMES = ['__ROOM_WALL__', '__ROOM_SIDE__', '__ROOM_FLOOR__', '__ROOM_CEILING__', '__ROOM_TOP__', '__ROOM_BOTTOM__'];

View File

@@ -21,8 +21,15 @@ onmessage = async (event) => {
babylonEngine.compatibilityMode = false;
babylonEngine.enableOfflineSupport = false;
await babylonEngine.initAsync();
engine = new RoomEngine(roomState, { canvas, engine: babylonEngine });
if (event.data.options.resolution === 2) babylonEngine.setHardwareScalingLevel(0.5);
if (event.data.options.resolution === 0.5) babylonEngine.setHardwareScalingLevel(2);
engine = new RoomEngine(roomState, { canvas, engine: babylonEngine, ...event.data.options });
engine.on('loadingProgress', ({ progress }) => {
self.postMessage({ type: 'progress', progress });
});
await engine.init();
self.postMessage({ type: 'inited' });
break;
}
case 'resize': {

View File

@@ -544,6 +544,8 @@ export class RecyvlingTextGrid {
}
export function sleep(ms: number) {
// workerで実行される可能性がある
// eslint-disable-next-line no-restricted-globals
return new Promise(resolve => setTimeout(resolve, ms));
}
@@ -552,7 +554,9 @@ export class Timer {
private intervalIds: number[] = [];
public setTimeout(callback: () => void, ms: number) {
const id = window.setTimeout(() => {
// workerで実行される可能性がある
// eslint-disable-next-line no-restricted-globals
const id = setTimeout(() => {
this.timeoutIds = this.timeoutIds.filter(i => i !== id);
callback();
}, ms);
@@ -560,18 +564,24 @@ export class Timer {
}
public setInterval(callback: () => void, ms: number) {
const id = window.setInterval(callback, ms);
// workerで実行される可能性がある
// eslint-disable-next-line no-restricted-globals
const id = setInterval(callback, ms);
this.intervalIds.push(id);
}
public dispose() {
for (const id of this.timeoutIds) {
window.clearTimeout(id);
// workerで実行される可能性がある
// eslint-disable-next-line no-restricted-globals
clearTimeout(id);
}
this.timeoutIds = [];
for (const id of this.intervalIds) {
window.clearInterval(id);
// workerで実行される可能性がある
// eslint-disable-next-line no-restricted-globals
clearInterval(id);
}
this.intervalIds = [];
}