1
0
mirror of https://github.com/misskey-dev/misskey.git synced 2026-05-13 16:25:44 +02:00
This commit is contained in:
syuilo
2026-04-08 20:34:35 +09:00
parent 5e1c0d1064
commit 1d8f03e199
2 changed files with 80 additions and 45 deletions

View File

@@ -10,7 +10,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<template v-if="!isZenMode">
<div v-if="engine != null" class="_buttonsCenter" :class="$style.overlayControls">
<template v-if="engine.isEditMode.value">
<template v-if="isEditMode">
<MkButton v-if="engine.ui.isGrabbing" @click="endGrabbing"><i class="ti ti-check"></i> (E)</MkButton>
<MkButton v-else-if="engine.ui.isGrabbingForInstall" @click="endGrabbing"><i class="ti ti-check"></i> (E)</MkButton>
<MkButton v-else-if="engine.selected.value != null" @click="beginSelectedInstalledObjectGrabbing"><i class="ti ti-hand-grab"></i> (E)</MkButton>
@@ -27,7 +27,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</template>
</div>
<div v-if="engine != null && engine.isEditMode.value && engine.selected.value != null" :key="engine.selected.value.objectId" class="_panel" :class="$style.overlayObjectInfoPanel">
<div v-if="engine != null && isEditMode && engine.selected.value != null" :key="engine.selected.value.objectId" class="_panel" :class="$style.overlayObjectInfoPanel">
{{ engine.selected.value.objectDef.name }}
<div class="_gaps">
@@ -58,10 +58,10 @@ SPDX-License-Identifier: AGPL-3.0-only
<div v-if="engine != null" class="_buttons" :class="$style.controls">
<!--<MkButton v-for="action in actions" :key="action.key" @click="action.fn">{{ action.label }}{{ hotkeyToLabel(action.hotkey) }}</MkButton>-->
<MkButton @click="toggleLight">Toggle Light</MkButton>
<MkButton :primary="engine.isEditMode.value" @click="toggleEditMode">Edit mode: {{ engine.isEditMode.value ? 'on' : 'off' }}</MkButton>
<MkButton @click="addObject">addObject</MkButton>
<MkButton primary @click="save">save</MkButton>
<MkButton @click="showBoundingBox">showBoundingBox</MkButton>
<MkButton v-if="isEditMode" primary @click="save">Save</MkButton>
<MkButton v-if="isEditMode" @click="exitEditMode">Exit edit mode</MkButton>
<MkButton v-if="!isEditMode" @click="enterEditMode">Edit mode</MkButton>
<MkButton v-if="isEditMode" @click="addObject">addObject</MkButton>
</div>
</template>
</div>
@@ -85,6 +85,8 @@ const canvas = useTemplateRef('canvas');
const engine = shallowRef<RoomEngine | null>(null);
const isEditMode = ref(false);
const interacions = shallowRef<{
id: string;
label: string;
@@ -118,7 +120,7 @@ const actions = computed<Action[]>(() => {
const actions: Action[] = [];
if (engine.value.isEditMode.value) {
if (isEditMode.value) {
actions.push({
key: 'grab',
label: 'Grab',
@@ -152,7 +154,7 @@ function onKeydown(ev: KeyboardEvent) {
if (ev.code === 'KeyE') {
ev.preventDefault();
ev.stopPropagation();
if (engine.value.isEditMode.value) {
if (isEditMode.value) {
if (engine.value.ui.isGrabbing || engine.value.ui.isGrabbingForInstall) {
endGrabbing();
} else {
@@ -349,11 +351,6 @@ function rotate() {
canvas.value!.focus();
}
function toggleEditMode() {
engine.value.isEditMode.value = !engine.value.isEditMode.value;
canvas.value!.focus();
}
async function addObject(ev: PointerEvent) {
if (engine.value == null) return;
const { dispose } = await os.popupAsyncWithDialog(import('./room.add-object-dialog.vue').then(x => x.default), {
@@ -376,6 +373,16 @@ function showBoundingBox() {
canvas.value!.focus();
}
function enterEditMode() {
engine.value?.enterEditMode();
isEditMode.value = true;
}
function exitEditMode() {
engine.value?.exitEditMode();
isEditMode.value = false;
}
function getHex(c: [number, number, number]) {
return `#${c.map(x => Math.round(x * 255).toString(16).padStart(2, '0')).join('')}`;
}

View File

@@ -452,15 +452,13 @@ export class RoomEngine {
private putParticleSystem: BABYLON.ParticleSystem;
private envMapIndoor: BABYLON.CubeTexture;
private envMapOutdoor: BABYLON.CubeTexture;
private reflectionProbe: BABYLON.ReflectionProbe;
private roomLight: BABYLON.SpotLight;
public lightContainer: BABYLON.ClusteredLightContainer;
private enableReflectionProbe = false; // NOTE: babylonのバグが仕様かは不明だが、WebGPUモードでは自分自身をrenderListに含むReflectionProbeを自分自身のreflectionTextureに設定するとエラーになる(WebGLモードでは問題なく動く) https://forum.babylonjs.com/t/in-webgpu-cannot-use-a-reflectionprobe-that-includes-itself-in-the-renderlist-as-a-reflectiontexture/63065
private xGridPreviewPlane: BABYLON.Mesh;
private yGridPreviewPlane: BABYLON.Mesh;
private zGridPreviewPlane: BABYLON.Mesh;
private selectionOutlineLayer: BABYLON.SelectionOutlineLayer | null = null;
public isEditMode = ref(false);
public isEditMode = false;
public isSitting = ref(false);
public ui = reactive({
isGrabbing: false,
@@ -512,21 +510,6 @@ export class RoomEngine {
this.envMapOutdoor = BABYLON.CubeTexture.CreateFromPrefilteredData(this.time === 2 ? '/client-assets/room/outdoor-night.env' : '/client-assets/room/outdoor-day.env', this.scene);
this.envMapOutdoor.level = this.time === 0 ? 0.5 : this.time === 1 ? 0.3 : 0.1;
if (this.enableReflectionProbe) {
this.reflectionProbe = new BABYLON.ReflectionProbe('reflectionProbe', 128, this.scene, true, true, true);
this.reflectionProbe.position = new BABYLON.Vector3(0, 150/*cm*/, 0);
this.reflectionProbe.refreshRate = 200;
}
//const sphere = BABYLON.MeshBuilder.CreateSphere('', { diameter: 50/*cm*/ }, this.scene);
//sphere.position = new BABYLON.Vector3(0, 100/*cm*/, 0);
//const mat = new BABYLON.PBRMaterial('', this.scene);
//mat.metallic = 1;
//mat.roughness = 0;
//mat.reflectionTexture = this.envMapIndoor;
//mat.reflectionTexture = this.reflectionProbe.cubeTexture;
//sphere.material = mat;
this.scene.collisionsEnabled = true;
this.camera = new BABYLON.UniversalCamera('camera', new BABYLON.Vector3(0, 130/*cm*/, 0/*cm*/), this.scene);
@@ -689,14 +672,6 @@ export class RoomEngine {
this.zGridPreviewPlane.isPickable = false;
this.zGridPreviewPlane.isVisible = false;
watch(this.isEditMode, (v) => {
if (v) {
for (const entity of this.objectEntities.values()) {
entity.instance.resetTemporaryState?.();
}
}
});
let isDragging = false;
this.canvas.addEventListener('pointerdown', (ev) => {
@@ -1034,10 +1009,9 @@ export class RoomEngine {
this.shadowGeneratorForSunLight.addShadowCaster(m);
//if (m.material) (m.material as BABYLON.PBRMaterial).ambientColor = new BABYLON.Color3(1, 1, 1);
if (m.material) {
(m.material as BABYLON.PBRMaterial).reflectionTexture = this.enableReflectionProbe ? this.reflectionProbe.cubeTexture : this.envMapIndoor;
(m.material as BABYLON.PBRMaterial).reflectionTexture = this.envMapIndoor;
(m.material as BABYLON.PBRMaterial).useGLTFLightFalloff = true; // Clustered Lightingではphysical falloffを持つマテリアルはアーチファクトが発生する https://doc.babylonjs.com/features/featuresDeepDive/lights/clusteredLighting/#materials-with-a-physical-falloff-may-cause-artefacts
}
if (this.enableReflectionProbe) this.reflectionProbe.renderList!.push(m);
}
}
}
@@ -1230,11 +1204,11 @@ export class RoomEngine {
if (mesh.material) {
if (mesh.material instanceof BABYLON.MultiMaterial) {
for (const subMat of mesh.material.subMaterials) {
(subMat as BABYLON.PBRMaterial).reflectionTexture = this.enableReflectionProbe ? this.reflectionProbe.cubeTexture : this.envMapIndoor;
(subMat as BABYLON.PBRMaterial).reflectionTexture = this.envMapIndoor;
(subMat as BABYLON.PBRMaterial).useGLTFLightFalloff = true; // Clustered Lightingではphysical falloffを持つマテリアルはアーチファクトが発生する https://doc.babylonjs.com/features/featuresDeepDive/lights/clusteredLighting/#materials-with-a-physical-falloff-may-cause-artefacts
}
} else {
(mesh.material as BABYLON.PBRMaterial).reflectionTexture = this.enableReflectionProbe ? this.reflectionProbe.cubeTexture : this.envMapIndoor;
(mesh.material as BABYLON.PBRMaterial).reflectionTexture = this.envMapIndoor;
(mesh.material as BABYLON.PBRMaterial).useGLTFLightFalloff = true; // Clustered Lightingではphysical falloffを持つマテリアルはアーチファクトが発生する https://doc.babylonjs.com/features/featuresDeepDive/lights/clusteredLighting/#materials-with-a-physical-falloff-may-cause-artefacts
}
}
@@ -1503,10 +1477,9 @@ export class RoomEngine {
}
public async addObject(type: string) {
if (!this.isEditMode) return;
if (this.grabbingCtx != null) return;
this.isEditMode.value = true;
const dir = this.camera.getDirection(BABYLON.Axis.Z).scale(this.scene.useRightHandedSystem ? -1 : 1);
const distance = 30/*cm*/;
@@ -1593,6 +1566,61 @@ export class RoomEngine {
});
}
public enterEditMode() {
this.isEditMode = true;
for (const entity of this.objectEntities.values()) {
entity.instance.resetTemporaryState?.();
}
}
public async exitEditMode() {
this.isEditMode = false;
await this.bake();
}
public async bake() {
/*
const reflectionProbe = new BABYLON.ReflectionProbe('', 256, this.scene, true, true, true);
reflectionProbe.position = new BABYLON.Vector3(0, 150, 0);
reflectionProbe.refreshRate = BABYLON.RenderTargetTexture.REFRESHRATE_RENDER_ONCE;
reflectionProbe.renderList = this.scene.meshes.filter(m => (m instanceof BABYLON.Mesh || m instanceof BABYLON.InstancedMesh) && m.isEnabled() && m.isVisible && m.material);
await new Promise(res => window.setTimeout(res, 1000));
const tex = reflectionProbe.cubeTexture;
const sphere = BABYLON.MeshBuilder.CreateSphere('', { diameter: 50 }, this.scene);
sphere.position = new BABYLON.Vector3(0, 100, 0);
const mat = new BABYLON.PBRMaterial('', this.scene);
mat.metallic = 1;
mat.roughness = 0;
mat.reflectionTexture = tex;
sphere.material = mat;
await new Promise(res => window.setTimeout(res, 3000));
reflectionProbe.renderList = [];
for (const mesh of this.scene.meshes.filter(m => (m instanceof BABYLON.Mesh || m instanceof BABYLON.InstancedMesh) && m.isEnabled() && m.isVisible && m.material && m.metadata?.isObject)) {
if (mesh.material) {
mesh.material.unfreeze();
if (mesh.material instanceof BABYLON.MultiMaterial) {
for (const subMat of mesh.material.subMaterials) {
subMat.unfreeze();
(subMat as BABYLON.PBRMaterial).reflectionTexture = tex;
(subMat as BABYLON.PBRMaterial).realTimeFiltering = true;
}
} else {
(mesh.material as BABYLON.PBRMaterial).reflectionTexture = tex;
(mesh.material as BABYLON.PBRMaterial).realTimeFiltering = true;
}
}
}
*/
}
public removeSelectedObject() {
if (this.selected.value == null) return;