1
0
mirror of https://github.com/misskey-dev/misskey.git synced 2026-05-14 07:35:35 +02:00
This commit is contained in:
syuilo
2026-02-10 10:47:22 +09:00
parent 491b40ed80
commit 3173290abb
2 changed files with 77 additions and 12 deletions

View File

@@ -37,6 +37,7 @@ onMounted(() => {
type: 'cardboard-box2', type: 'cardboard-box2',
position: [120, 31, 50], position: [120, 31, 50],
rotation: [0, 0.1, 0], rotation: [0, 0.1, 0],
sticky: 'a',
}, { }, {
id: '1', id: '1',
type: 'cardboard-box', type: 'cardboard-box',

View File

@@ -240,7 +240,7 @@ export class RoomEngine {
private camera: BABYLON.UniversalCamera; private camera: BABYLON.UniversalCamera;
private camera2: BABYLON.ArcRotateCamera; private camera2: BABYLON.ArcRotateCamera;
private intervalIds: number[] = []; private intervalIds: number[] = [];
private objects: Map<string, BABYLON.AbstractMesh> = new Map(); private objectMeshs: Map<string, BABYLON.AbstractMesh> = new Map();
private grabbing: BABYLON.AbstractMesh | null = null; private grabbing: BABYLON.AbstractMesh | null = null;
private grabbingStartDistance: number | null = null; private grabbingStartDistance: number | null = null;
private grabbingGhost: BABYLON.AbstractMesh | null = null; private grabbingGhost: BABYLON.AbstractMesh | null = null;
@@ -389,17 +389,24 @@ export class RoomEngine {
const mesh = this.scene.pick(this.scene.pointerX, this.scene.pointerY)?.pickedMesh; const mesh = this.scene.pick(this.scene.pointerX, this.scene.pointerY)?.pickedMesh;
if (mesh != null) { if (mesh != null) {
const oid = mesh.metadata.objectId; const oid = mesh.metadata.objectId;
if (oid != null && this.objects.has(oid)) { if (oid != null && this.objectMeshs.has(oid)) {
const o = this.objects.get(oid)!; const o = this.objectMeshs.get(oid)!;
// focus camera // focus camera
this.camera.setTarget(o.position); this.camera.setTarget(o.position);
} }
} }
}); });
this.canvas.addEventListener('keypress', (ev) => {
if (ev.code === 'KeyE') {
ev.preventDefault();
ev.stopPropagation();
this.grab();
}
});
if (_DEV_) { if (_DEV_) {
const axes = new AxesViewer(this.scene, 5); const axes = new AxesViewer(this.scene, 30);
axes.scaleLines = 30;
axes.xAxis.position = new BABYLON.Vector3(0, 30, 0); axes.xAxis.position = new BABYLON.Vector3(0, 30, 0);
axes.yAxis.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); axes.zAxis.position = new BABYLON.Vector3(0, 30, 0);
@@ -432,17 +439,17 @@ export class RoomEngine {
private handleSeeking() { private handleSeeking() {
this.highlightedObjectId = null; this.highlightedObjectId = null;
const ray = new BABYLON.Ray(this.camera.position, this.camera.getDirection(BABYLON.Axis.Z), 1000/*cm*/); const ray = new BABYLON.Ray(this.camera.position, this.camera.getDirection(BABYLON.Axis.Z), 1000/*cm*/);
for (const [id, o] of this.objects.entries()) { for (const [id, o] of this.objectMeshs.entries()) {
for (const om of o.getChildMeshes()) { for (const om of o.getChildMeshes()) {
om.renderOutline = false; om.renderOutline = false;
} }
} }
const hit = this.scene.pickWithRay(ray)!; const hit = this.scene.pickWithRay(ray)!;
if (hit.pickedMesh != null) { if (hit.pickedMesh != null) {
const oid = hit.pickedMesh.metadata.objectId; const oid = hit.pickedMesh.metadata?.objectId;
if (oid != null && this.objects.has(oid)) { if (oid != null && this.objectMeshs.has(oid)) {
this.highlightedObjectId = oid; this.highlightedObjectId = oid;
const o = this.objects.get(oid)!; const o = this.objectMeshs.get(oid)!;
for (const om of o.getChildMeshes()) { for (const om of o.getChildMeshes()) {
om.renderOutline = true; om.renderOutline = true;
} }
@@ -454,7 +461,10 @@ export class RoomEngine {
const dir = this.camera.getDirection(BABYLON.Axis.Z); const dir = this.camera.getDirection(BABYLON.Axis.Z);
this.grabbingGhost.position = this.camera.position.add(dir.scale(this.grabbingStartDistance)); this.grabbingGhost.position = this.camera.position.add(dir.scale(this.grabbingStartDistance));
const stickyObjectIds = Array.from(this.def.objects.filter(o => o.sticky === this.grabbing!.metadata.objectId)).map(o => o.id);
let y = 0; let y = 0;
let sticky = null;
for (const rcmb of this.roomCollisionMeshes.filter(m => m.name.startsWith('_COLLISION_FLOOR_'))) { for (const rcmb of this.roomCollisionMeshes.filter(m => m.name.startsWith('_COLLISION_FLOOR_'))) {
const rcb = rcmb.getBoundingInfo().boundingBox; const rcb = rcmb.getBoundingInfo().boundingBox;
@@ -469,7 +479,25 @@ export class RoomEngine {
} }
} }
for (const [id, o] of this.objects.entries().filter(([_id, o]) => o !== this.grabbing)) { const isStickyChild = (parent: BABYLON.AbstractMesh, target: BABYLON.AbstractMesh): boolean => {
const stickyObjectIds = Array.from(this.def.objects.filter(o => o.sticky === parent.metadata.objectId)).map(o => o.id);
for (const soid of stickyObjectIds) {
if (soid === target.metadata.objectId) return true;
const soMesh = this.objectMeshs.get(soid)!;
if (isStickyChild(soMesh, target)) return true;
}
return false;
};
const checkObjectEntries = this.objectMeshs.entries()
.filter(([_id, o]) => {
if (o === this.grabbing) return false;
if (stickyObjectIds.includes(_id)) return false;
if (isStickyChild(this.grabbing!, o)) return false;
return true;
});
for (const [id, o] of checkObjectEntries) {
for (const om of o.getChildMeshes()) { for (const om of o.getChildMeshes()) {
const omb = om.getBoundingInfo().boundingBox; const omb = om.getBoundingInfo().boundingBox;
for (const tm of this.grabbing.getChildMeshes()) { for (const tm of this.grabbing.getChildMeshes()) {
@@ -478,12 +506,19 @@ export class RoomEngine {
const topY = omb.maximumWorld.y; const topY = omb.maximumWorld.y;
if (y === 0 || topY > y) { if (y === 0 || topY > y) {
y = topY; y = topY;
sticky = id;
} }
} }
} }
} }
} }
if (sticky != null) {
this.def.objects.find(o => o.id === this.grabbing!.metadata.objectId)!.sticky = sticky;
} else {
this.def.objects.find(o => o.id === this.grabbing!.metadata.objectId)!.sticky = null;
}
this.grabbing.position = this.grabbingGhost.position.clone(); this.grabbing.position = this.grabbingGhost.position.clone();
//this.grabbing.position.x = Math.min(Math.max(this.grabbing.position.x, -(this.ROOM_SIZE / 2)), (this.ROOM_SIZE / 2)); //this.grabbing.position.x = Math.min(Math.max(this.grabbing.position.x, -(this.ROOM_SIZE / 2)), (this.ROOM_SIZE / 2));
//this.grabbing.position.z = Math.min(Math.max(this.grabbing.position.z, -(this.ROOM_SIZE / 2)), (this.ROOM_SIZE / 2)); //this.grabbing.position.z = Math.min(Math.max(this.grabbing.position.z, -(this.ROOM_SIZE / 2)), (this.ROOM_SIZE / 2));
@@ -507,6 +542,12 @@ export class RoomEngine {
//); //);
//this.grabbing.moveWithCollisions(displacementVector); //this.grabbing.moveWithCollisions(displacementVector);
//this.grabbing.position.y = y; //this.grabbing.position.y = y;
for (const soid of stickyObjectIds) {
//const soMesh = this.objectMeshs.get(soid)!;
//const offset = this.grabbing!.position.subtract(soMeshStartPosition);
//soMesh.position = this.grabbing!.position.subtract(offset);
}
} }
private async loadEnvModel() { private async loadEnvModel() {
@@ -566,7 +607,7 @@ export class RoomEngine {
mesh.outlineColor = new BABYLON.Color3(1, 0, 0); mesh.outlineColor = new BABYLON.Color3(1, 0, 0);
} }
this.objects.set(id, obj.meshes[0]); this.objectMeshs.set(id, obj.meshes[0]);
const objDef = OBJECTS[type]; const objDef = OBJECTS[type];
if (objDef != null && objDef.onInit != null) { if (objDef != null && objDef.onInit != null) {
@@ -576,6 +617,17 @@ export class RoomEngine {
public grab() { public grab() {
if (this.grabbing != null) { if (this.grabbing != null) {
// 親から先に外していく
const removeStickyParentRecursively = (mesh: BABYLON.AbstractMesh) => {
const stickyObjectIds = Array.from(this.def.objects.filter(o => o.sticky === mesh.metadata.objectId)).map(o => o.id);
for (const soid of stickyObjectIds) {
const soMesh = this.objectMeshs.get(soid)!;
soMesh.parent = null;
soMesh.position = soMesh.position.add(mesh.position);
removeStickyParentRecursively(soMesh);
}
};
removeStickyParentRecursively(this.grabbing);
this.grabbing = null; this.grabbing = null;
this.grabbingStartDistance = null; this.grabbingStartDistance = null;
if (this.grabbingGhost != null) { if (this.grabbingGhost != null) {
@@ -585,7 +637,7 @@ export class RoomEngine {
return; return;
} }
if (this.highlightedObjectId == null) return; if (this.highlightedObjectId == null) return;
const highlightedObject = this.objects.get(this.highlightedObjectId)!; const highlightedObject = this.objectMeshs.get(this.highlightedObjectId)!;
this.grabbing = highlightedObject; this.grabbing = highlightedObject;
this.grabbingStartDistance = BABYLON.Vector3.Distance(this.camera.position, highlightedObject.position); this.grabbingStartDistance = BABYLON.Vector3.Distance(this.camera.position, highlightedObject.position);
this.grabbingGhost = highlightedObject.clone('ghost', null, false); this.grabbingGhost = highlightedObject.clone('ghost', null, false);
@@ -598,6 +650,18 @@ export class RoomEngine {
m.material = mat; m.material = mat;
} }
} }
// 子から先に適用していく
const setStickyParentRecursively = (mesh: BABYLON.AbstractMesh) => {
const stickyObjectIds = Array.from(this.def.objects.filter(o => o.sticky === mesh.metadata.objectId)).map(o => o.id);
for (const soid of stickyObjectIds) {
const soMesh = this.objectMeshs.get(soid)!;
setStickyParentRecursively(soMesh);
soMesh.parent = mesh;
soMesh.position = soMesh.position.subtract(mesh.position);
}
};
setStickyParentRecursively(this.grabbing);
} }
public destroy() { public destroy() {