1
0
mirror of https://github.com/misskey-dev/misskey.git synced 2026-05-18 16:35:30 +02:00
This commit is contained in:
syuilo
2026-05-09 13:52:45 +09:00
parent 179c9fc70a
commit 3605ffdafc
9 changed files with 43 additions and 14 deletions

View File

@@ -883,6 +883,7 @@ export class RoomEngine extends EventEmitter {
const objectInstance = await def.createInstance({ const objectInstance = await def.createInstance({
room: this, room: this,
scene: this.scene, scene: this.scene,
sr: this.sr,
root, root,
options: args.options, options: args.options,
model, model,

View File

@@ -114,6 +114,7 @@ export type ObjectDef<OpSc extends OptionsSchema = OptionsSchema> = {
createInstance: (args: { createInstance: (args: {
room?: RoomEngine | null; room?: RoomEngine | null;
scene: BABYLON.Scene; scene: BABYLON.Scene;
sr: BABYLON.SnapshotRenderingHelper;
root: BABYLON.Mesh; root: BABYLON.Mesh;
options: Readonly<GetOptionsSchemaValues<OpSc>>; options: Readonly<GetOptionsSchemaValues<OpSc>>;
model: ModelManager; model: ModelManager;

View File

@@ -24,7 +24,7 @@ export const ceilingFanLight = defineObject({
hasCollisions: false, hasCollisions: false,
receiveShadows: false, receiveShadows: false,
castShadows: false, castShadows: false,
createInstance: ({ options, room, scene, model }) => { createInstance: ({ options, sr, scene, model }) => {
const shadeMaterial = model.findMaterial('__X_SHADE__'); const shadeMaterial = model.findMaterial('__X_SHADE__');
const applyShadeColor = () => { const applyShadeColor = () => {
@@ -49,7 +49,7 @@ export const ceilingFanLight = defineObject({
]); ]);
rotor.animations = [anim]; rotor.animations = [anim];
animationObserver = scene.onAfterAnimationsObservable.add(() => { animationObserver = scene.onAfterAnimationsObservable.add(() => {
room?.sr.updateMesh([rotor, ...rotor.getChildMeshes()], false); sr.updateMesh([rotor, ...rotor.getChildMeshes()], false);
}); });
scene.beginAnimation(rotor, 0, 100, true); scene.beginAnimation(rotor, 0, 100, true);
}, },

View File

@@ -39,7 +39,7 @@ export const lavaLamp = defineObject({
placement: 'top', placement: 'top',
hasCollisions: false, hasCollisions: false,
canPreMeshesMerging: true, canPreMeshesMerging: true,
createInstance: ({ options, room, scene, root, model, graphicsQuality }) => { createInstance: ({ options, room, scene, sr, root, model, graphicsQuality }) => {
const bodyMaterial = model.findMaterial('__X_BODY__'); const bodyMaterial = model.findMaterial('__X_BODY__');
const glassMaterial = model.findMaterial('__X_GLASS__'); const glassMaterial = model.findMaterial('__X_GLASS__');
const lightMaterial = model.findMaterial('__X_LIGHT__'); const lightMaterial = model.findMaterial('__X_LIGHT__');
@@ -111,7 +111,7 @@ export const lavaLamp = defineObject({
scene.beginAnimation(sphere3, 0, 800, true, 0.6); scene.beginAnimation(sphere3, 0, 800, true, 0.6);
animationObserver = scene.onAfterAnimationsObservable.add(() => { animationObserver = scene.onAfterAnimationsObservable.add(() => {
room?.sr.updateMesh([sphere, sphere2, sphere3], false); sr.updateMesh([sphere, sphere2, sphere3], false);
}); });
const emitter = new BABYLON.TransformNode('emitter', scene); const emitter = new BABYLON.TransformNode('emitter', scene);
@@ -139,7 +139,7 @@ export const lavaLamp = defineObject({
ps.preWarmCycles = 100; ps.preWarmCycles = 100;
ps.start(); ps.start();
room?.sr.fixParticleSystem(ps); sr.fixParticleSystem(ps);
return { return {
onInited: () => { onInited: () => {

View File

@@ -15,7 +15,7 @@ export const radiometer = defineObject({
}, },
placement: 'top', placement: 'top',
hasCollisions: false, hasCollisions: false,
createInstance: ({ room, scene, model }) => { createInstance: ({ sr, scene, model }) => {
const vanes = model.findTransformNode('__X_VANES__'); const vanes = model.findTransformNode('__X_VANES__');
model.bakeExcludeMeshes = [...vanes.getChildMeshes()]; model.bakeExcludeMeshes = [...vanes.getChildMeshes()];
@@ -31,7 +31,7 @@ export const radiometer = defineObject({
]); ]);
vanes.animations = [anim]; vanes.animations = [anim];
animationObserver = scene.onAfterAnimationsObservable.add(() => { animationObserver = scene.onAfterAnimationsObservable.add(() => {
room?.sr.updateMesh([...vanes.getChildMeshes()], true); sr.updateMesh([...vanes.getChildMeshes()], true);
}); });
scene.beginAnimation(vanes, 0, 240, true); scene.beginAnimation(vanes, 0, 240, true);
}, },

View File

@@ -35,7 +35,7 @@ export const tabletopDigitalClock = defineObject({
placement: 'top', placement: 'top',
hasCollisions: false, hasCollisions: false,
canPreMeshesMerging: false, canPreMeshesMerging: false,
createInstance: ({ root, room, options, model, scene, timer }) => { createInstance: ({ sr, options, model, timer }) => {
const matrix = model.root.getWorldMatrix(true); const matrix = model.root.getWorldMatrix(true);
const scale = new BABYLON.Vector3(); const scale = new BABYLON.Vector3();
matrix.decompose(scale); matrix.decompose(scale);
@@ -123,7 +123,7 @@ export const tabletopDigitalClock = defineObject({
mesh.position.y = isVisible ? defaultSegMeshDepth : defaultSegMeshDepth - (cm(2) / Math.abs(scale.y)); mesh.position.y = isVisible ? defaultSegMeshDepth : defaultSegMeshDepth - (cm(2) / Math.abs(scale.y));
} }
room?.sr.updateMesh([...Object.values(segmentMeshes), ...colonMeshes]); sr.updateMesh([...Object.values(segmentMeshes), ...colonMeshes]);
}, 1000); }, 1000);
}, },
onOptionsUpdated: ([k, v]) => { onOptionsUpdated: ([k, v]) => {

View File

@@ -22,7 +22,7 @@ export const wallClock = defineObject({
}, },
placement: 'side', placement: 'side',
hasCollisions: false, hasCollisions: false,
createInstance: ({ room, timer, options, model }) => { createInstance: ({ sr, timer, options, model }) => {
const hourHand = model.findMesh('HandH'); const hourHand = model.findMesh('HandH');
const minuteHand = model.findMesh('HandM'); const minuteHand = model.findMesh('HandM');
@@ -48,7 +48,7 @@ export const wallClock = defineObject({
const mAngle = -(minutes / 60) * Math.PI * 2; const mAngle = -(minutes / 60) * Math.PI * 2;
hourHand.rotation = new BABYLON.Vector3(0, 0, hAngle); hourHand.rotation = new BABYLON.Vector3(0, 0, hAngle);
minuteHand.rotation = new BABYLON.Vector3(0, 0, mAngle); minuteHand.rotation = new BABYLON.Vector3(0, 0, mAngle);
room?.sr.updateMesh([hourHand, minuteHand], false); sr.updateMesh([hourHand, minuteHand], false);
}, 1000); }, 1000);
}, },
onOptionsUpdated: ([k, v]) => { onOptionsUpdated: ([k, v]) => {

View File

@@ -26,6 +26,7 @@ export class RoomObjectPreviewEngine {
private canvas: HTMLCanvasElement; private canvas: HTMLCanvasElement;
private engine: BABYLON.WebGPUEngine; private engine: BABYLON.WebGPUEngine;
private scene: BABYLON.Scene; private scene: BABYLON.Scene;
private sr: BABYLON.SnapshotRenderingHelper;
private shadowGenerator: BABYLON.ShadowGenerator; private shadowGenerator: BABYLON.ShadowGenerator;
private camera: BABYLON.ArcRotateCamera; private camera: BABYLON.ArcRotateCamera;
private objectMesh: BABYLON.Mesh | null = null; private objectMesh: BABYLON.Mesh | null = null;
@@ -50,10 +51,11 @@ export class RoomObjectPreviewEngine {
this.engine = options.engine; this.engine = options.engine;
this.scene = new BABYLON.Scene(this.engine); this.scene = new BABYLON.Scene(this.engine);
this.scene.clearColor = new BABYLON.Color4(0, 0, 0, 0); this.scene.autoClear = false;
this.scene.autoClear = true;
this.scene.skipPointerMovePicking = true; this.scene.skipPointerMovePicking = true;
this.sr = new BABYLON.SnapshotRenderingHelper(this.scene);
this.camera = new BABYLON.ArcRotateCamera('camera', -Math.PI / 2, Math.PI / 2.5, cm(300), new BABYLON.Vector3(0, cm(90), 0), this.scene); this.camera = new BABYLON.ArcRotateCamera('camera', -Math.PI / 2, Math.PI / 2.5, cm(300), new BABYLON.Vector3(0, cm(90), 0), this.scene);
this.envMapIndoor = BABYLON.CubeTexture.CreateFromPrefilteredData('/client-assets/room/indoor.env', this.scene); this.envMapIndoor = BABYLON.CubeTexture.CreateFromPrefilteredData('/client-assets/room/indoor.env', this.scene);
@@ -95,6 +97,7 @@ export class RoomObjectPreviewEngine {
}); });
gl.intensity = 0.5; gl.intensity = 0.5;
this.scene.setRenderingAutoClearDepthStencil(gl.renderingGroupId, false); this.scene.setRenderingAutoClearDepthStencil(gl.renderingGroupId, false);
this.sr.updateMeshesForEffectLayer(gl);
this.pipeline = new BABYLON.DefaultRenderingPipeline('default', true, this.scene); this.pipeline = new BABYLON.DefaultRenderingPipeline('default', true, this.scene);
this.pipeline.samples = 4; this.pipeline.samples = 4;
@@ -188,10 +191,12 @@ export class RoomObjectPreviewEngine {
} }
public async init() { public async init() {
// 特になし await this.scene.whenReadyAsync();
this.sr.enableSnapshotRendering();
} }
public async load(type: string) { public async load(type: string) {
this.sr.disableSnapshotRendering();
this.clear(); this.clear();
const id = genId(); const id = genId();
@@ -254,6 +259,8 @@ export class RoomObjectPreviewEngine {
this.pipeline.addCamera(this.camera); this.pipeline.addCamera(this.camera);
this.sr.enableSnapshotRendering();
return { return {
id, id,
objectInstance: this.objectInstance, objectInstance: this.objectInstance,
@@ -317,6 +324,10 @@ export class RoomObjectPreviewEngine {
const model = new ModelManager(subRoot, loaderResult.meshes.filter(m => !m.isDisposed() && m !== subRoot), def.hasTexture, (meshes) => { const model = new ModelManager(subRoot, loaderResult.meshes.filter(m => !m.isDisposed() && m !== subRoot), def.hasTexture, (meshes) => {
updateMeshes(meshes); updateMeshes(meshes);
}); });
//model.updatedCallback = () => {
// this.sr.disableSnapshotRendering();
// this.sr.enableSnapshotRendering();
//};
updateMeshes(subRoot.getChildMeshes()); updateMeshes(subRoot.getChildMeshes());
@@ -325,6 +336,7 @@ export class RoomObjectPreviewEngine {
const objectInstance = await def.createInstance({ const objectInstance = await def.createInstance({
room: null, room: null,
scene: this.scene, scene: this.scene,
sr: this.sr,
root, root,
options: args.options, options: args.options,
model, model,
@@ -341,12 +353,15 @@ export class RoomObjectPreviewEngine {
} }
public updateObjectOption(key: string, value: any) { public updateObjectOption(key: string, value: any) {
this.sr.disableSnapshotRendering();
this.objectOptions[key] = value; this.objectOptions[key] = value;
this.objectInstance?.onOptionsUpdated?.([key, value]); this.objectInstance?.onOptionsUpdated?.([key, value]);
this.sr.enableSnapshotRendering();
return this.objectOptions; return this.objectOptions;
} }
public clear() { public clear() {
this.sr.disableSnapshotRendering();
if (this.timerForEachObject != null) { if (this.timerForEachObject != null) {
this.timerForEachObject.dispose(); this.timerForEachObject.dispose();
this.timerForEachObject = null; this.timerForEachObject = null;
@@ -359,10 +374,20 @@ export class RoomObjectPreviewEngine {
this.objectMesh = null; this.objectMesh = null;
this.objectType = null; this.objectType = null;
} }
this.sr.enableSnapshotRendering();
} }
public resize() { public resize() {
// 一旦snapshot renderingを無効にしておかないとエラーが出る(babylonのバグ)
// ~~...が、一旦無効にしたらしたで複数のマテリアルがそれぞれ入れ替わる(?)という謎の現象が発生するためコメントアウトしとく(エラー出てもレンダリングが止まったりするわけでもないし)~~
// ↑追記: engine.resizeした後に一瞬待つことで回避できることが判明
this.sr.disableSnapshotRendering();
this.engine.resize(); this.engine.resize();
// workerで実行される可能性がある
// eslint-disable-next-line no-restricted-globals
setTimeout(() => {
this.sr.enableSnapshotRendering();
}, 1);
} }
public destroy() { public destroy() {

View File

@@ -203,6 +203,7 @@ export function findMaterial(rootMesh: BABYLON.AbstractMesh, keyword: string, al
export class ModelManager { export class ModelManager {
public root: BABYLON.Mesh; public root: BABYLON.Mesh;
public bakedCallback: (() => void) | null = null; public bakedCallback: (() => void) | null = null;
public updatedCallback: (() => void) | null = null;
public bakeExcludeMeshes: BABYLON.Mesh[] = []; public bakeExcludeMeshes: BABYLON.Mesh[] = [];
private originalMeshes: BABYLON.Mesh[] = []; private originalMeshes: BABYLON.Mesh[] = [];
private bakedMeshes: BABYLON.Mesh[] = []; private bakedMeshes: BABYLON.Mesh[] = [];
@@ -241,6 +242,7 @@ export class ModelManager {
} }
public updated() { public updated() {
this.updatedCallback?.();
} }
public bakeMesh() { public bakeMesh() {