diff --git a/packages/frontend/assets/room/rooms/default/300.glb b/packages/frontend/assets/room/rooms/default/300.glb
index b7cbcaa77c..4c3c3598fc 100644
Binary files a/packages/frontend/assets/room/rooms/default/300.glb and b/packages/frontend/assets/room/rooms/default/300.glb differ
diff --git a/packages/frontend/assets/room/rooms/default/default.blend b/packages/frontend/assets/room/rooms/default/default.blend
index c2506e3b7f..7aee1bebf6 100644
Binary files a/packages/frontend/assets/room/rooms/default/default.blend and b/packages/frontend/assets/room/rooms/default/default.blend differ
diff --git a/packages/frontend/src/pages/room.default-heya-options.vue b/packages/frontend/src/pages/room.default-heya-options.vue
new file mode 100644
index 0000000000..e69de29bb2
diff --git a/packages/frontend/src/pages/room.vue b/packages/frontend/src/pages/room.vue
index c25e544567..146549fba4 100644
--- a/packages/frontend/src/pages/room.vue
+++ b/packages/frontend/src/pages/room.vue
@@ -98,6 +98,26 @@ SPDX-License-Identifier: AGPL-3.0-only
{ const c = getRgb(v); if (c != null) controller.updateHeyaOptions({ ...controller.roomState.value.heya.options, wallN: { ...controller.roomState.value.heya.options.wallN, color: c } }); }">
color
+
+ { controller.updateHeyaOptions({ ...controller.roomState.value.heya.options, wallN: { ...controller.roomState.value.heya.options.wallN, withHari: v } }); }">
+ with Hari
+
+ { controller.updateHeyaOptions({ ...controller.roomState.value.heya.options, wallN: { ...controller.roomState.value.heya.options.wallN, hariMaterial: v } }); }"
+ >
+ hari material
+
+ { const c = getRgb(v); if (c != null) controller.updateHeyaOptions({ ...controller.roomState.value.heya.options, wallN: { ...controller.roomState.value.heya.options.wallN, hariColor: c } }); }">
+ hari color
+
+
+ { controller.updateHeyaOptions({ ...controller.roomState.value.heya.options, wallN: { ...controller.roomState.value.heya.options.wallN, withHabaki: v } }); }">
+ with Habaki
+
Wall E
@@ -113,6 +133,26 @@ SPDX-License-Identifier: AGPL-3.0-only
{ const c = getRgb(v); if (c != null) controller.updateHeyaOptions({ ...controller.roomState.value.heya.options, wallE: { ...controller.roomState.value.heya.options.wallE, color: c } }); }">
color
+
+
{ controller.updateHeyaOptions({ ...controller.roomState.value.heya.options, wallE: { ...controller.roomState.value.heya.options.wallE, withHari: v } }); }">
+ with Hari
+
+
{ controller.updateHeyaOptions({ ...controller.roomState.value.heya.options, wallE: { ...controller.roomState.value.heya.options.wallE, hariMaterial: v } }); }"
+ >
+ hari material
+
+
{ const c = getRgb(v); if (c != null) controller.updateHeyaOptions({ ...controller.roomState.value.heya.options, wallE: { ...controller.roomState.value.heya.options.wallE, hariColor: c } }); }">
+ hari color
+
+
+
{ controller.updateHeyaOptions({ ...controller.roomState.value.heya.options, wallE: { ...controller.roomState.value.heya.options.wallE, withHabaki: v } }); }">
+ with Habaki
+
Wall S
@@ -128,6 +168,26 @@ SPDX-License-Identifier: AGPL-3.0-only
{ const c = getRgb(v); if (c != null) controller.updateHeyaOptions({ ...controller.roomState.value.heya.options, wallS: { ...controller.roomState.value.heya.options.wallS, color: c } }); }">
color
+
+
{ controller.updateHeyaOptions({ ...controller.roomState.value.heya.options, wallS: { ...controller.roomState.value.heya.options.wallS, withHari: v } }); }">
+ with Hari
+
+
{ controller.updateHeyaOptions({ ...controller.roomState.value.heya.options, wallS: { ...controller.roomState.value.heya.options.wallS, hariMaterial: v } }); }"
+ >
+ hari material
+
+
{ const c = getRgb(v); if (c != null) controller.updateHeyaOptions({ ...controller.roomState.value.heya.options, wallS: { ...controller.roomState.value.heya.options.wallS, hariColor: c } }); }">
+ hari color
+
+
+
{ controller.updateHeyaOptions({ ...controller.roomState.value.heya.options, wallS: { ...controller.roomState.value.heya.options.wallS, withHabaki: v } }); }">
+ with Habaki
+
Wall W
@@ -143,6 +203,26 @@ SPDX-License-Identifier: AGPL-3.0-only
{ const c = getRgb(v); if (c != null) controller.updateHeyaOptions({ ...controller.roomState.value.heya.options, wallW: { ...controller.roomState.value.heya.options.wallW, color: c } }); }">
color
+
+
{ controller.updateHeyaOptions({ ...controller.roomState.value.heya.options, wallW: { ...controller.roomState.value.heya.options.wallW, withHari: v } }); }">
+ with Hari
+
+
{ controller.updateHeyaOptions({ ...controller.roomState.value.heya.options, wallW: { ...controller.roomState.value.heya.options.wallW, hariMaterial: v } }); }"
+ >
+ hari material
+
+
{ const c = getRgb(v); if (c != null) controller.updateHeyaOptions({ ...controller.roomState.value.heya.options, wallW: { ...controller.roomState.value.heya.options.wallW, hariColor: c } }); }">
+ hari color
+
+
+
{ controller.updateHeyaOptions({ ...controller.roomState.value.heya.options, wallW: { ...controller.roomState.value.heya.options.wallW, withHabaki: v } }); }">
+ with Habaki
+
@@ -260,6 +340,12 @@ const data = localStorage.getItem('roomData') != null ? JSON.parse(localStorage.
installedObjects: [],
};
+// 後方互換性のため
+if (data.heya.options.wallE.hariColor == null) data.heya.options.wallE.hariColor = [0.8, 0.8, 0.8];
+if (data.heya.options.wallN.hariColor == null) data.heya.options.wallN.hariColor = [0.8, 0.8, 0.8];
+if (data.heya.options.wallS.hariColor == null) data.heya.options.wallS.hariColor = [0.8, 0.8, 0.8];
+if (data.heya.options.wallW.hariColor == null) data.heya.options.wallW.hariColor = [0.8, 0.8, 0.8];
+
let latestData = deepClone(data);
const roomControllerOptions = computed(() => ({
@@ -754,6 +840,9 @@ definePage(() => ({
padding: 16px;
box-sizing: border-box;
width: 300px;
+ max-height: 100%;
+ box-sizing: border-box;
+ overflow: auto;
}
.loading {
diff --git a/packages/frontend/src/world/room/heya.ts b/packages/frontend/src/world/room/heya.ts
index b599739065..6e3af00568 100644
--- a/packages/frontend/src/world/room/heya.ts
+++ b/packages/frontend/src/world/room/heya.ts
@@ -29,6 +29,10 @@ export abstract class HeyaManager {
type SimpleHeyaWallBase = {
material: null | 'wood' | 'concrete';
color: [number, number, number];
+ withHari: boolean;
+ hariMaterial: null | 'wood' | 'concrete';
+ hariColor: [number, number, number];
+ withHabaki: boolean;
};
export type SimpleHeyaOptions = {
@@ -63,6 +67,10 @@ export class SimpleHeyaManager extends HeyaManager {
private wallSMaterial: BABYLON.PBRMaterial | null = null;
private wallWMaterial: BABYLON.PBRMaterial | null = null;
private wallEMaterial: BABYLON.PBRMaterial | null = null;
+ private wallNHariMaterial: BABYLON.PBRMaterial | null = null;
+ private wallSHariMaterial: BABYLON.PBRMaterial | null = null;
+ private wallWHariMaterial: BABYLON.PBRMaterial | null = null;
+ private wallEHariMaterial: BABYLON.PBRMaterial | null = null;
constructor(onMeshUpdatedCallback?: ((meshes: BABYLON.AbstractMesh[]) => void) | null) {
super(onMeshUpdatedCallback);
@@ -120,46 +128,105 @@ export class SimpleHeyaManager extends HeyaManager {
m.material = this.wallEMaterial;
}
+ const hariMaterial = findMaterial(this.meshes[0], '__X_HARI__');
+ this.wallNHariMaterial = hariMaterial.clone('wallNHariMaterial');
+ this.wallSHariMaterial = hariMaterial.clone('wallSHariMaterial');
+ this.wallWHariMaterial = hariMaterial.clone('wallWHariMaterial');
+ this.wallEHariMaterial = hariMaterial.clone('wallEHariMaterial');
+
+ for (const m of this.wallNRoot.getChildMeshes().filter(m => m.material === hariMaterial)) {
+ m.material = this.wallNHariMaterial;
+ }
+ for (const m of this.wallSRoot.getChildMeshes().filter(m => m.material === hariMaterial)) {
+ m.material = this.wallSHariMaterial;
+ }
+ for (const m of this.wallWRoot.getChildMeshes().filter(m => m.material === hariMaterial)) {
+ m.material = this.wallWHariMaterial;
+ }
+ for (const m of this.wallERoot.getChildMeshes().filter(m => m.material === hariMaterial)) {
+ m.material = this.wallEHariMaterial;
+ }
+
await this.applyOptions(options);
}
public applyOptions(options: SimpleHeyaOptions) {
// TODO: 返り値をpromiseにしてちゃんとテクスチャが読み終わってからresolveする
- const apply = (wall: 'N' | 'S' | 'W' | 'E') => {
+ const applyWall = (wall: 'N' | 'S' | 'W' | 'E') => {
+ const wallRoot =
+ wall === 'N' ? this.wallNRoot :
+ wall === 'S' ? this.wallSRoot :
+ wall === 'W' ? this.wallWRoot :
+ this.wallERoot;
+
const wallOptions =
wall === 'N' ? options.wallN :
wall === 'S' ? options.wallS :
wall === 'W' ? options.wallW :
options.wallE;
- const targetMaterial =
- wall === 'N' ? this.wallNMaterial :
- wall === 'S' ? this.wallSMaterial :
- wall === 'W' ? this.wallWMaterial :
- this.wallEMaterial;
- targetMaterial.unfreeze();
-
- targetMaterial.albedoColor = new BABYLON.Color3(...wallOptions.color);
-
- const texPath = wallOptions.material === 'wood' ? '/client-assets/room/wall-textures/wood.png'
- : wallOptions.material === 'concrete' ? '/client-assets/room/wall-textures/concrete.png'
- : null;
-
- if (texPath != null) {
- const tex = new BABYLON.Texture(texPath, this.meshes[0].getScene(), false, false);
- targetMaterial.albedoTexture = tex;
- } else {
- targetMaterial.albedoTexture = null;
+ for (const mesh of wallRoot.getChildMeshes()) {
+ if (mesh.name.includes('__X_HARI__')) {
+ mesh.isVisible = wallOptions.withHari;
+ } else if (mesh.name.includes('__X_HABAKI__')) {
+ mesh.isVisible = wallOptions.withHabaki;
+ }
}
- targetMaterial.freeze();
+ {
+ const targetMaterial =
+ wall === 'N' ? this.wallNMaterial :
+ wall === 'S' ? this.wallSMaterial :
+ wall === 'W' ? this.wallWMaterial :
+ this.wallEMaterial;
+
+ targetMaterial.unfreeze();
+ targetMaterial.albedoColor = new BABYLON.Color3(...wallOptions.color);
+
+ const texPath = wallOptions.material === 'wood' ? '/client-assets/room/wall-textures/wood.png'
+ : wallOptions.material === 'concrete' ? '/client-assets/room/wall-textures/concrete.png'
+ : null;
+
+ if (texPath != null) {
+ const tex = new BABYLON.Texture(texPath, this.meshes[0].getScene(), false, false);
+ targetMaterial.albedoTexture = tex;
+ } else {
+ targetMaterial.albedoTexture = null;
+ }
+
+ targetMaterial.freeze();
+ }
+
+ {
+ const targetMaterial =
+ wall === 'N' ? this.wallNHariMaterial :
+ wall === 'S' ? this.wallSHariMaterial :
+ wall === 'W' ? this.wallWHariMaterial :
+ this.wallEHariMaterial;
+
+ targetMaterial.unfreeze();
+ targetMaterial.albedoColor = new BABYLON.Color3(...wallOptions.hariColor);
+
+ const texPath = wallOptions.hariMaterial === 'wood' ? '/client-assets/room/wall-textures/wood.png'
+ : wallOptions.hariMaterial === 'concrete' ? '/client-assets/room/wall-textures/concrete.png'
+ : null;
+
+ if (texPath != null) {
+ const tex = new BABYLON.Texture(texPath, this.meshes[0].getScene(), false, false);
+ targetMaterial.albedoTexture = tex;
+ } else {
+ targetMaterial.albedoTexture = null;
+ }
+
+ targetMaterial.freeze();
+ }
};
- apply('N');
- apply('S');
- apply('W');
- apply('E');
+ applyWall('N');
+ applyWall('S');
+ applyWall('W');
+ applyWall('E');
this.onMeshUpdatedCallback?.(this.meshes);
}