了解。
あなたが言う 「階層構造でメッシュを管理し、上位メッシュをシンボリックリンクし、拡大・細分化・編集できる」 という要求は、Three.jsでも完全に実現できる。
しかも、あなたの OS 的なレイヤー設計と非常に相性が良い。
ここでは、現実に動く・拡張しやすい・AI統合しやすい という3条件を満たす Three.js メッシュ階層OS を設計する。
🧩 Three.js で実現する「メッシュ階層OS」設計
1. 全体構造(OSレイヤー)
MeshOS
├─ NodeLayer(階層構造)
│ ├─ MeshNode(実体)
│ └─ LinkNode(シンボリックリンク)
├─ LODLayer(拡大・細分化)
├─ EditLayer(編集)
└─ AILayer(構造生成)
あなたのアプリの思想をそのままWebに移植した形。
2. NodeLayer:階層構造の中核
■ MeshNode(実体ノード)
Three.js の Group をベースにする。
- 子ノードを持てる
- 自身のローカル変換(位置・回転・スケール)
- メッシュ(BufferGeometry)を保持
class MeshNode extends THREE.Group {
geometry?: THREE.BufferGeometry;
material?: THREE.Material;
constructor(geometry?: THREE.BufferGeometry, material?: THREE.Material) {
super();
this.geometry = geometry;
this.material = material;
if (geometry && material) {
const mesh = new THREE.Mesh(geometry, material);
this.add(mesh);
}
}
}
■ LinkNode(シンボリックリンク)
Three.js には「参照コピー」がないので、インスタンス化(InstanceMesh) を使う。
- 元メッシュを参照
- 変換だけ独立
- 編集は元メッシュに反映
class LinkNode extends THREE.Group {
constructor(public target: MeshNode) {
super();
const inst = new THREE.InstancedMesh(
target.geometry!,
target.material!,
1
);
inst.setMatrixAt(0, new THREE.Matrix4());
this.add(inst);
}
}
これで「上位メッシュをリンクして配置」が可能。
3. LODLayer:拡大表示・細分化
■ LOD(Level of Detail)をノード単位で持つ
MeshNode に LOD を持たせる。
MeshNode
├─ lod0(粗い)
├─ lod1(中)
└─ lod2(細かい)
Three.js の THREE.LOD を使うか、独自管理でもOK。
class MeshNode extends THREE.Group {
lodLevels: THREE.Mesh[] = [];
addLOD(mesh: THREE.Mesh, distance: number) {
const lod = new THREE.LOD();
lod.addLevel(mesh, distance);
this.add(lod);
this.lodLevels.push(mesh);
}
}
■ 細分化(Subdivision)
Three.js には SubdivisionModifier がある。
import { SubdivisionModifier } from 'three/examples/jsm/modifiers/SubdivisionModifier.js';
function subdivide(geometry: THREE.BufferGeometry, level: number) {
const modifier = new SubdivisionModifier(level);
return modifier.modify(geometry.clone());
}
LOD2 を生成するときに使う。
4. EditLayer:編集機能
■ 選択
- Raycaster で MeshNode を取得
- LinkNode を選択した場合は target にフォーカス
■ 編集
- TransformControls で位置・回転・スケール
- 頂点編集は BufferGeometry の position を直接操作
function editVertex(geometry, index, newPos) {
const pos = geometry.attributes.position;
pos.setXYZ(index, newPos.x, newPos.y, newPos.z);
pos.needsUpdate = true;
}
5. AILayer:構造生成との接続
AI が返す JSON を MeshNode の階層構造に変換する。
AI出力例
{
"nodes": [
{
"id": "body",
"primitive": "cylinder",
"children": [
{ "id": "head", "primitive": "sphere" },
{ "id": "leg1", "link": "leg" },
{ "id": "leg2", "link": "leg" }
]
},
{
"id": "leg",
"primitive": "cylinder"
}
]
}
ローダ
function loadStructure(json) {
const nodeMap = new Map();
// 実体ノードを先に作る
json.nodes.forEach(n => {
if (!n.link) {
nodeMap.set(n.id, new MeshNode(createPrimitive(n.primitive)));
}
});
// リンクノードを作る
json.nodes.forEach(n => {
if (n.link) {
nodeMap.set(n.id, new LinkNode(nodeMap.get(n.link)));
}
});
// 階層構造を構築
json.nodes.forEach(n => {
const node = nodeMap.get(n.id);
if (n.children) {
n.children.forEach(c => node.add(nodeMap.get(c.id)));
}
});
return nodeMap.get("root") || [...nodeMap.values()][0];
}
6. これで何ができるか
✔ メッシュを階層構造で管理
UI でツリー表示可能。
✔ 上位メッシュをシンボリックリンク
脚6本の昆虫などが一瞬で作れる。
✔ 拡大表示
LOD 切り替えで細かい編集が可能。
✔ 細分化
SubdivisionModifier で局所的に細かくできる。
✔ 編集
TransformControls + 頂点編集で自由に変形。
✔ AI との接続
AI は「構造(ノードツリー)」だけ返せばよい。
次に詰めるべきはどれか選んでほしい
- 階層ノードのUI(ツリー表示+選択)
- LODの自動生成(AIがLOD0→LOD2を作る)
- Subdivisionの適用ルール(どの部位を細分化するか)
- AI JSON仕様の確定(StructureSpecの正式版)
- LinkNodeの最適化(InstanceMeshの扱い)
どれを深掘りしたいか教えてくれたら、次のレイヤーを設計するよ。