@fmsim/machine 2.0.0-beta.100 → 2.0.0-beta.104
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/factories/agv-3d.js +9 -27
- package/dist/factories/agv-3d.js.map +1 -1
- package/dist/factories/conveyor-3d.js +11 -19
- package/dist/factories/conveyor-3d.js.map +1 -1
- package/dist/factories/crane-3d.js +8 -17
- package/dist/factories/crane-3d.js.map +1 -1
- package/dist/factories/crane-rail-3d.js +8 -12
- package/dist/factories/crane-rail-3d.js.map +1 -1
- package/dist/factories/machine-3d.js +20 -30
- package/dist/factories/machine-3d.js.map +1 -1
- package/dist/factories/oht-3d.js +9 -27
- package/dist/factories/oht-3d.js.map +1 -1
- package/dist/factories/shuttle-3d.js +11 -27
- package/dist/factories/shuttle-3d.js.map +1 -1
- package/dist/mcs-machine.js +4 -23
- package/dist/mcs-machine.js.map +1 -1
- package/dist/mcs-unit.js +2 -5
- package/dist/mcs-unit.js.map +1 -1
- package/dist/scene/root-container-override.js +2 -0
- package/dist/scene/root-container-override.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +2 -2
- package/src/factories/agv-3d.ts +10 -26
- package/src/factories/conveyor-3d.ts +12 -19
- package/src/factories/crane-3d.ts +9 -17
- package/src/factories/crane-rail-3d.ts +9 -13
- package/src/factories/machine-3d.ts +35 -34
- package/src/factories/oht-3d.ts +10 -26
- package/src/factories/shuttle-3d.ts +12 -26
- package/src/mcs-machine.ts +4 -23
- package/src/mcs-unit.ts +2 -5
- package/src/scene/root-container-override.ts +2 -0
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@fmsim/machine",
|
|
3
3
|
"description": "Layout View를 구성하는 설비(machine)들과 유닛을 구현한 모듈입니다.",
|
|
4
4
|
"author": "heartyoh",
|
|
5
|
-
"version": "2.0.0-beta.
|
|
5
|
+
"version": "2.0.0-beta.104",
|
|
6
6
|
"main": "dist/index.js",
|
|
7
7
|
"module": "dist/index.js",
|
|
8
8
|
"things-scene": true,
|
|
@@ -55,5 +55,5 @@
|
|
|
55
55
|
"prettier --write"
|
|
56
56
|
]
|
|
57
57
|
},
|
|
58
|
-
"gitHead": "
|
|
58
|
+
"gitHead": "9fd007d34fca773bdf6aa56f06f2ff9b189133d8"
|
|
59
59
|
}
|
package/src/factories/agv-3d.ts
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
|
|
16
16
|
import * as THREE from 'three'
|
|
17
17
|
import { RoundedBoxGeometry } from 'three/examples/jsm/geometries/RoundedBoxGeometry.js'
|
|
18
|
-
import { RealObjectGroup, registerRealObjectFactory, disposeObject3D } from '@hatiolab/things-scene'
|
|
18
|
+
import { RealObjectGroup, registerRealObjectFactory, disposeObject3D, MaterialBank } from '@hatiolab/things-scene'
|
|
19
19
|
import type { Component } from '@hatiolab/things-scene'
|
|
20
20
|
import { TRANSPORT_SURFACE_HEIGHT } from './machine-3d.js'
|
|
21
21
|
|
|
@@ -76,11 +76,8 @@ export class AGV3D extends RealObjectGroup {
|
|
|
76
76
|
const bumperPad = Math.min(w, h) * 0.03
|
|
77
77
|
const bumperCornerR = Math.min(w + bumperPad * 2, h + bumperPad * 2, bumperH) * 0.2
|
|
78
78
|
const bumperGeo = new RoundedBoxGeometry(w + bumperPad * 2, bumperH, h + bumperPad * 2, 4, bumperCornerR)
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
roughness: 0.8,
|
|
82
|
-
metalness: 0.1,
|
|
83
|
-
})
|
|
79
|
+
// MaterialBank 공유 — dedup + faint 안전(코어 변형 스왑, disposeObject3D 가 __bankOwned 스킵).
|
|
80
|
+
const bumperMat = MaterialBank.material('agv|bumper', { roughness: 0.8, metalness: 0.1 }, BUMPER_COLOR)
|
|
84
81
|
const bumper = new THREE.Mesh(bumperGeo, bumperMat)
|
|
85
82
|
bumper.position.y = bumperH / 2
|
|
86
83
|
bumper.castShadow = true
|
|
@@ -89,11 +86,7 @@ export class AGV3D extends RealObjectGroup {
|
|
|
89
86
|
// ── 본체 (둥근 모서리, statusColor 적용) ──
|
|
90
87
|
const bodyColor = this.resolveColor()
|
|
91
88
|
const bodyGeo = new RoundedBoxGeometry(w, bodyH, h, 4, cornerR)
|
|
92
|
-
const bodyMat =
|
|
93
|
-
color: bodyColor,
|
|
94
|
-
roughness: 0.3,
|
|
95
|
-
metalness: 0.5,
|
|
96
|
-
})
|
|
89
|
+
const bodyMat = MaterialBank.material('agv|body', { roughness: 0.3, metalness: 0.5 }, bodyColor)
|
|
97
90
|
const body = new THREE.Mesh(bodyGeo, bodyMat)
|
|
98
91
|
body.position.y = bumperH + bodyH / 2
|
|
99
92
|
body.castShadow = true
|
|
@@ -103,11 +96,7 @@ export class AGV3D extends RealObjectGroup {
|
|
|
103
96
|
const platInset = Math.min(w, h) * 0.04
|
|
104
97
|
const platCornerR = Math.min(w - platInset * 2, h - platInset * 2, platH) * 0.15
|
|
105
98
|
const platGeo = new RoundedBoxGeometry(w - platInset * 2, platH, h - platInset * 2, 4, platCornerR)
|
|
106
|
-
const platMat =
|
|
107
|
-
color: PLATFORM_COLOR,
|
|
108
|
-
roughness: 0.5,
|
|
109
|
-
metalness: 0.15,
|
|
110
|
-
})
|
|
99
|
+
const platMat = MaterialBank.material('agv|platform', { roughness: 0.5, metalness: 0.15 }, PLATFORM_COLOR)
|
|
111
100
|
const plat = new THREE.Mesh(platGeo, platMat)
|
|
112
101
|
plat.position.y = bumperH + bodyH + gapH + platH / 2
|
|
113
102
|
plat.castShadow = true
|
|
@@ -116,6 +105,9 @@ export class AGV3D extends RealObjectGroup {
|
|
|
116
105
|
this._ownMeshes = [bumper, body, plat]
|
|
117
106
|
// ownGroup이 center-origin ↔ bottom-up 좌표계 변환을 자동 처리
|
|
118
107
|
for (const m of this._ownMeshes) this.components3D.add(m)
|
|
108
|
+
|
|
109
|
+
// mesh 는 super.build() 이후 생성 → 코어 faint 를 명시 적용(편집 흐림이 mesh 에 닿게).
|
|
110
|
+
this.updateAlpha()
|
|
119
111
|
}
|
|
120
112
|
|
|
121
113
|
updateDimension() {}
|
|
@@ -134,16 +126,8 @@ export class AGV3D extends RealObjectGroup {
|
|
|
134
126
|
this.updateHidden()
|
|
135
127
|
}
|
|
136
128
|
|
|
137
|
-
updateAlpha()
|
|
138
|
-
|
|
139
|
-
for (const m of this._ownMeshes) {
|
|
140
|
-
const materials = Array.isArray(m.material) ? m.material : [m.material]
|
|
141
|
-
for (const mat of materials) {
|
|
142
|
-
;(mat as THREE.MeshStandardMaterial).opacity = alpha
|
|
143
|
-
;(mat as THREE.MeshStandardMaterial).transparent = alpha < 1
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
}
|
|
129
|
+
// updateAlpha override 제거 — 코어 RealObject.updateAlpha(=applyMaterialOpacity)로 수렴.
|
|
130
|
+
// canonical(bank base opacity 1) × state.alpha × faint. view 모드 불변, 편집 모드 faint 추가.
|
|
147
131
|
|
|
148
132
|
onchange(after: Record<string, unknown>, before: Record<string, unknown>) {
|
|
149
133
|
if ('width' in after || 'height' in after || 'depth' in after ||
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
|
|
14
14
|
import * as THREE from 'three'
|
|
15
15
|
import * as BufferGeometryUtils from 'three/examples/jsm/utils/BufferGeometryUtils.js'
|
|
16
|
-
import { RealObjectGroup, registerRealObjectFactory } from '@hatiolab/things-scene'
|
|
16
|
+
import { RealObjectGroup, registerRealObjectFactory, MaterialBank } from '@hatiolab/things-scene'
|
|
17
17
|
import type { Component } from '@hatiolab/things-scene'
|
|
18
18
|
import { TRANSPORT_SURFACE_HEIGHT } from './machine-3d.js'
|
|
19
19
|
import { Z_FMSIM } from './z-priority'
|
|
@@ -85,11 +85,8 @@ export class Conveyor3D extends RealObjectGroup {
|
|
|
85
85
|
const railW = Math.max(beltWidth * 0.06, 2)
|
|
86
86
|
const legThickness = Math.max(railW * 0.8, 2)
|
|
87
87
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
metalness: 0.85,
|
|
91
|
-
roughness: 0.35,
|
|
92
|
-
})
|
|
88
|
+
// MaterialBank 공유(dedup). 자체 update() 없이 base 생명주기(guarded disposeObject3D) 상속 → 안전.
|
|
89
|
+
const frameMaterial = MaterialBank.material('conveyor|frame', { metalness: 0.85, roughness: 0.35 }, FRAME_COLOR)
|
|
93
90
|
|
|
94
91
|
// --- Frame: side rails + legs + cross-bracing ---
|
|
95
92
|
// Y 좌표: y=0(바닥) ~ y=depth(상단). 레일 상단이 depth에 위치.
|
|
@@ -179,6 +176,9 @@ export class Conveyor3D extends RealObjectGroup {
|
|
|
179
176
|
} else {
|
|
180
177
|
this.buildRollers(width, height, depth, frameH, railW, rollWidth, isVertical)
|
|
181
178
|
}
|
|
179
|
+
|
|
180
|
+
// mesh 는 super.build() 이후 생성 → 코어 faint 를 명시 적용(편집 흐림이 mesh 에 닿게).
|
|
181
|
+
this.updateAlpha()
|
|
182
182
|
}
|
|
183
183
|
|
|
184
184
|
private buildRollers(
|
|
@@ -231,7 +231,7 @@ export class Conveyor3D extends RealObjectGroup {
|
|
|
231
231
|
if (rollerGeometries.length > 0) {
|
|
232
232
|
const rollerMesh = new THREE.Mesh(
|
|
233
233
|
BufferGeometryUtils.mergeGeometries(rollerGeometries),
|
|
234
|
-
|
|
234
|
+
MaterialBank.material('conveyor|roller', { metalness: 0.9, roughness: 0.2 }, color)
|
|
235
235
|
)
|
|
236
236
|
rollerMesh.castShadow = true
|
|
237
237
|
this.components3D.add(rollerMesh)
|
|
@@ -268,18 +268,14 @@ export class Conveyor3D extends RealObjectGroup {
|
|
|
268
268
|
|
|
269
269
|
const drumMesh = new THREE.Mesh(
|
|
270
270
|
BufferGeometryUtils.mergeGeometries(drumGeometries),
|
|
271
|
-
|
|
271
|
+
MaterialBank.material('conveyor|drum', { metalness: 0.9, roughness: 0.2 }, ROLLER_COLOR)
|
|
272
272
|
)
|
|
273
273
|
drumMesh.castShadow = true
|
|
274
274
|
this.components3D.add(drumMesh)
|
|
275
275
|
|
|
276
276
|
// Belt surface
|
|
277
277
|
const beltThickness = drumRadius * 0.12
|
|
278
|
-
const beltMaterial =
|
|
279
|
-
color: color,
|
|
280
|
-
metalness: 0.0,
|
|
281
|
-
roughness: 0.9,
|
|
282
|
-
})
|
|
278
|
+
const beltMaterial = MaterialBank.material('conveyor|belt', { metalness: 0.0, roughness: 0.9 }, color)
|
|
283
279
|
|
|
284
280
|
// Flat belt top surface spanning between drums
|
|
285
281
|
const flatLen = drum2 - drum1
|
|
@@ -347,11 +343,7 @@ export class Conveyor3D extends RealObjectGroup {
|
|
|
347
343
|
// 두 레일 간격: 내부 폭의 60%
|
|
348
344
|
const railSpacing = innerWidth * 0.6
|
|
349
345
|
|
|
350
|
-
const railMaterial =
|
|
351
|
-
color,
|
|
352
|
-
metalness: 0.7,
|
|
353
|
-
roughness: 0.3,
|
|
354
|
-
})
|
|
346
|
+
const railMaterial = MaterialBank.material('conveyor|rail', { metalness: 0.7, roughness: 0.3 }, color)
|
|
355
347
|
|
|
356
348
|
const railGeometries: THREE.BufferGeometry[] = []
|
|
357
349
|
|
|
@@ -376,7 +368,8 @@ export class Conveyor3D extends RealObjectGroup {
|
|
|
376
368
|
}
|
|
377
369
|
|
|
378
370
|
updateDimension() {}
|
|
379
|
-
updateAlpha()
|
|
371
|
+
// updateAlpha override 제거 — 코어 RealObject.updateAlpha(=applyMaterialOpacity)로 수렴(faint).
|
|
372
|
+
// view 모드는 factor=1 → build-시 opacity 그대로(불변), 편집 모드만 faint 추가.
|
|
380
373
|
|
|
381
374
|
onchange(after: Record<string, unknown>, before: Record<string, unknown>) {
|
|
382
375
|
if (
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
|
|
14
14
|
import * as THREE from 'three'
|
|
15
15
|
import * as BufferGeometryUtils from 'three/examples/jsm/utils/BufferGeometryUtils.js'
|
|
16
|
-
import { RealObjectGroup, registerRealObjectFactory } from '@hatiolab/things-scene'
|
|
16
|
+
import { RealObjectGroup, registerRealObjectFactory, MaterialBank } from '@hatiolab/things-scene'
|
|
17
17
|
import type { Component } from '@hatiolab/things-scene'
|
|
18
18
|
import { TRANSPORT_SURFACE_HEIGHT } from './machine-3d.js'
|
|
19
19
|
|
|
@@ -84,11 +84,8 @@ export class Crane3D extends RealObjectGroup {
|
|
|
84
84
|
|
|
85
85
|
const pillarThick = Math.min(w, h) * 0.12
|
|
86
86
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
roughness: 0.5,
|
|
90
|
-
metalness: 0.5,
|
|
91
|
-
})
|
|
87
|
+
// MaterialBank 공유(dedup). 자체 update() 없이 base 생명주기(guarded disposeObject3D) 상속 → 안전.
|
|
88
|
+
const clampMat = MaterialBank.material('crane|clamp', { roughness: 0.5, metalness: 0.5 }, CLAMP_COLOR)
|
|
92
89
|
|
|
93
90
|
// ── 1. 하단 클램프 (바닥 레일에 물리는 바퀴부) ──
|
|
94
91
|
const clampW = w * 0.7
|
|
@@ -102,11 +99,7 @@ export class Crane3D extends RealObjectGroup {
|
|
|
102
99
|
// ── 2. 수직 마스트 (좌우 기둥 + 상·하 가로 연결 바) ──
|
|
103
100
|
const mastBaseY = clampH
|
|
104
101
|
const bodyColor = this.resolveColor()
|
|
105
|
-
const mastMat =
|
|
106
|
-
color: bodyColor,
|
|
107
|
-
roughness: 0.3,
|
|
108
|
-
metalness: 0.6,
|
|
109
|
-
})
|
|
102
|
+
const mastMat = MaterialBank.material('crane|mast', { roughness: 0.3, metalness: 0.6 }, bodyColor)
|
|
110
103
|
|
|
111
104
|
const mastGeometries: THREE.BufferGeometry[] = []
|
|
112
105
|
|
|
@@ -137,11 +130,7 @@ export class Crane3D extends RealObjectGroup {
|
|
|
137
130
|
// 포크 geometry 는 *_mastBaseY 기준 local 0 에 둠* — 즉 group.position.y = 0
|
|
138
131
|
// 일 때 mast 바닥 자리에. forkZ 0~100 에 따라 group.position.y 만 변경하면
|
|
139
132
|
// mast 따라 위/아래 이동. mesh 재구축 불필요.
|
|
140
|
-
const forkMat =
|
|
141
|
-
color: FORK_COLOR,
|
|
142
|
-
roughness: 0.4,
|
|
143
|
-
metalness: 0.5,
|
|
144
|
-
})
|
|
133
|
+
const forkMat = MaterialBank.material('crane|fork', { roughness: 0.4, metalness: 0.5 }, FORK_COLOR)
|
|
145
134
|
|
|
146
135
|
const forkGeometries: THREE.BufferGeometry[] = []
|
|
147
136
|
|
|
@@ -188,10 +177,13 @@ export class Crane3D extends RealObjectGroup {
|
|
|
188
177
|
topClamp.position.y = mastBaseY + mastH + clampH / 2
|
|
189
178
|
topClamp.castShadow = true
|
|
190
179
|
inner.add(topClamp)
|
|
180
|
+
|
|
181
|
+
// mesh 는 super.build() 이후 생성 → 코어 faint 를 명시 적용(편집 흐림이 mesh 에 닿게).
|
|
182
|
+
this.updateAlpha()
|
|
191
183
|
}
|
|
192
184
|
|
|
193
185
|
updateDimension() {}
|
|
194
|
-
updateAlpha()
|
|
186
|
+
// updateAlpha override 제거 — 코어 RealObject.updateAlpha(=applyMaterialOpacity)로 수렴(faint).
|
|
195
187
|
|
|
196
188
|
/** build() 직전 호출. forkGroup 참조를 깨끗이 비워둔다 — 새 build 가 다시 set. */
|
|
197
189
|
clear() {
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
import * as THREE from 'three'
|
|
14
14
|
import * as BufferGeometryUtils from 'three/examples/jsm/utils/BufferGeometryUtils.js'
|
|
15
|
-
import { RealObjectGroup, registerRealObjectFactory } from '@hatiolab/things-scene'
|
|
15
|
+
import { RealObjectGroup, registerRealObjectFactory, MaterialBank } from '@hatiolab/things-scene'
|
|
16
16
|
import type { Component } from '@hatiolab/things-scene'
|
|
17
17
|
import { TRANSPORT_SURFACE_HEIGHT } from './machine-3d.js'
|
|
18
18
|
import { Z_FMSIM } from './z-priority'
|
|
@@ -46,17 +46,10 @@ export class CraneRail3D extends RealObjectGroup {
|
|
|
46
46
|
const railW = Math.max(h * 0.06, 2) // 레일 폭
|
|
47
47
|
const supportThick = Math.max(Math.min(w, h) * 0.05, 2)
|
|
48
48
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
})
|
|
54
|
-
|
|
55
|
-
const supportMat = new THREE.MeshStandardMaterial({
|
|
56
|
-
color: SUPPORT_COLOR,
|
|
57
|
-
roughness: 0.5,
|
|
58
|
-
metalness: 0.5,
|
|
59
|
-
})
|
|
49
|
+
// MaterialBank 공유(정적 색 dedup). 자체 update() 없이 base 생명주기(guarded disposeObject3D)
|
|
50
|
+
// 상속 → 공유 base dispose 안전.
|
|
51
|
+
const railMat = MaterialBank.material('crane-rail|rail', { roughness: 0.3, metalness: 0.7 }, RAIL_COLOR)
|
|
52
|
+
const supportMat = MaterialBank.material('crane-rail|support', { roughness: 0.5, metalness: 0.5 }, SUPPORT_COLOR)
|
|
60
53
|
|
|
61
54
|
// ── 바닥 레일 (2개 평행 트랙) ──
|
|
62
55
|
const bottomGeometries: THREE.BufferGeometry[] = []
|
|
@@ -98,10 +91,13 @@ export class CraneRail3D extends RealObjectGroup {
|
|
|
98
91
|
const supportMesh = new THREE.Mesh(BufferGeometryUtils.mergeGeometries(supportGeometries), supportMat)
|
|
99
92
|
supportMesh.castShadow = true
|
|
100
93
|
inner.add(supportMesh)
|
|
94
|
+
|
|
95
|
+
// mesh 는 super.build() 이후 생성 → 코어 faint 를 명시 적용(편집 흐림이 mesh 에 닿게).
|
|
96
|
+
this.updateAlpha()
|
|
101
97
|
}
|
|
102
98
|
|
|
103
99
|
updateDimension() {}
|
|
104
|
-
updateAlpha()
|
|
100
|
+
// updateAlpha override 제거 — 코어 RealObject.updateAlpha(=applyMaterialOpacity)로 수렴(faint).
|
|
105
101
|
|
|
106
102
|
onchange(after: Record<string, unknown>, before: Record<string, unknown>) {
|
|
107
103
|
if ('width' in after || 'height' in after || 'depth' in after || 'fillStyle' in after || 'strokeStyle' in after) {
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
|
|
11
11
|
import * as THREE from 'three'
|
|
12
12
|
import * as BufferGeometryUtils from 'three/examples/jsm/utils/BufferGeometryUtils.js'
|
|
13
|
-
import { RealObjectGroup, registerRealObjectFactory, disposeObject3D } from '@hatiolab/things-scene'
|
|
13
|
+
import { RealObjectGroup, registerRealObjectFactory, disposeObject3D, MaterialBank } from '@hatiolab/things-scene'
|
|
14
14
|
import type { Component } from '@hatiolab/things-scene'
|
|
15
15
|
import { LEGEND_CAPACITY, resolveCarrierLegend } from '../features/mcs-status-default'
|
|
16
16
|
import { getValueOnRanges } from '../utils/get-value-on-ranges'
|
|
@@ -312,23 +312,30 @@ class MCSRealObject3D extends RealObjectGroup {
|
|
|
312
312
|
: this.buildBoxGeometry(w, depth, h)
|
|
313
313
|
|
|
314
314
|
const isPlane = shape === 'plane'
|
|
315
|
-
|
|
315
|
+
// Standard body 는 MaterialBank 공유(색 변형) — 인스턴스 dedup + faint 안전(코어가 공유 base 의
|
|
316
|
+
// 변형만 스왑, 원본 base 불변). plane 은 unlit MeshBasicMaterial 이라 bank(Standard 전용) 비대상 → raw.
|
|
317
|
+
const material: THREE.Material = isPlane
|
|
316
318
|
? new THREE.MeshBasicMaterial({
|
|
317
319
|
color,
|
|
318
320
|
opacity,
|
|
319
321
|
transparent: opacity < 1,
|
|
320
322
|
side: THREE.DoubleSide,
|
|
321
323
|
})
|
|
322
|
-
:
|
|
324
|
+
: MaterialBank.material(
|
|
325
|
+
'mcs|body',
|
|
326
|
+
{
|
|
327
|
+
metalness,
|
|
328
|
+
roughness,
|
|
329
|
+
opacity,
|
|
330
|
+
side: opacity < 1 ? THREE.DoubleSide : THREE.FrontSide,
|
|
331
|
+
...(this._config.emissiveIntensity
|
|
332
|
+
? { emissive: color, emissiveIntensity: this._config.emissiveIntensity }
|
|
333
|
+
: {}),
|
|
334
|
+
},
|
|
323
335
|
color,
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
transparent: opacity < 1,
|
|
328
|
-
side: opacity < 1 ? THREE.DoubleSide : THREE.FrontSide,
|
|
329
|
-
...(this._config.emissiveIntensity ? { emissive: color, emissiveIntensity: this._config.emissiveIntensity } : {}),
|
|
330
|
-
})
|
|
331
|
-
// z-fighting 방지: 바닥면(floor grid)보다 항상 앞에 렌더링
|
|
336
|
+
)
|
|
337
|
+
// z-fighting 방지: 바닥면(floor grid)보다 앞. bank body 는 공유 base 라 polygonOffset 은 모든 mcs
|
|
338
|
+
// body 공통 상수 — 반환 material 에 세팅(같은 값이라 멱등, 인스턴스별 발산 없음).
|
|
332
339
|
material.polygonOffset = true
|
|
333
340
|
material.polygonOffsetFactor = -1
|
|
334
341
|
material.polygonOffsetUnit = -1
|
|
@@ -360,6 +367,11 @@ class MCSRealObject3D extends RealObjectGroup {
|
|
|
360
367
|
this._ownMesh.castShadow = !isPlane
|
|
361
368
|
this._ownMesh.receiveShadow = true
|
|
362
369
|
this.components3D.add(this._ownMesh)
|
|
370
|
+
|
|
371
|
+
// mesh 는 super.build() *이후* 생성되므로, 코어의 build-시점 faint 적용이 이 mesh 에 못 닿는다.
|
|
372
|
+
// mesh 생성 직후 명시 적용 — 코어 applyMaterialOpacity 가 content-alpha × faint 를 일괄 처리.
|
|
373
|
+
// view 모드에선 factor=1(=state.alpha 없음) → canonical(config.opacity) 그대로, 고객 화면 불변.
|
|
374
|
+
this.updateAlpha()
|
|
363
375
|
}
|
|
364
376
|
|
|
365
377
|
// ── Change handling ──
|
|
@@ -468,22 +480,10 @@ class MCSRealObject3D extends RealObjectGroup {
|
|
|
468
480
|
// RealObjectGroup 기본 동작 비활성화
|
|
469
481
|
updateDimension() {}
|
|
470
482
|
|
|
471
|
-
updateAlpha()
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
this.object3d.traverse((o: any) => {
|
|
477
|
-
if (!o.material) return
|
|
478
|
-
const materials = Array.isArray(o.material) ? o.material : [o.material]
|
|
479
|
-
for (const m of materials) {
|
|
480
|
-
if (!m.visible) continue // openTop invisible face 무시
|
|
481
|
-
if (m.map) continue // 텍스처 material은 자체 transparent 유지
|
|
482
|
-
m.opacity = effective
|
|
483
|
-
m.transparent = effective < 1
|
|
484
|
-
}
|
|
485
|
-
})
|
|
486
|
-
}
|
|
483
|
+
// updateAlpha override 제거 — 코어 RealObject.updateAlpha(=applyMaterialOpacity)로 수렴.
|
|
484
|
+
// 코어가 canonical(=build 시 config.opacity 로 만든 material) 위에 factor = state.alpha × faint 를
|
|
485
|
+
// 공유 변형 스왑으로 일괄 적용한다(원본 base 불변). 기존 in-place 변이는 (1) faint 미적용,
|
|
486
|
+
// (2) 코어 applyFocusDim 과 이중 적용 소지가 있어 방언이었다. config.opacity 는 canonical 로 보존.
|
|
487
487
|
}
|
|
488
488
|
|
|
489
489
|
// ── 헬퍼 ────────────────────────────────────────────────
|
|
@@ -573,11 +573,9 @@ class OHTLineRealObject3D extends RealObjectGroup {
|
|
|
573
573
|
const webH = beamH - flangeH * 2 // 웹 높이
|
|
574
574
|
const webW = Math.max(flangeW * 0.25, 1) // 웹 두께
|
|
575
575
|
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
roughness: 0.4,
|
|
580
|
-
})
|
|
576
|
+
// 공유 base(MaterialBank) — OHTLine rail 은 정적 색이라 전 인스턴스 dedup. faint 는 코어가
|
|
577
|
+
// 공유 base 의 변형을 스왑(원본 불변). dispose 는 bank-safe(update 에서 material.dispose 안 함).
|
|
578
|
+
const mat = MaterialBank.material('oht-line|rail', { metalness: 0.5, roughness: 0.4 }, OHT_LINE_RAIL_COLOR)
|
|
581
579
|
|
|
582
580
|
const geoms: THREE.BufferGeometry[] = []
|
|
583
581
|
|
|
@@ -605,13 +603,16 @@ class OHTLineRealObject3D extends RealObjectGroup {
|
|
|
605
603
|
this._mesh = new THREE.Mesh(BufferGeometryUtils.mergeGeometries(geoms), mat)
|
|
606
604
|
this._mesh.castShadow = true
|
|
607
605
|
this.object3d.add(this._mesh)
|
|
606
|
+
|
|
607
|
+
// mesh 가 super.build() 이후 생성 → 코어 faint 를 명시 적용(편집 흐림이 mesh 에 닿게).
|
|
608
|
+
this.updateAlpha()
|
|
608
609
|
}
|
|
609
610
|
|
|
610
611
|
update() {
|
|
611
612
|
if (this._mesh) {
|
|
612
613
|
this.object3d.remove(this._mesh)
|
|
613
614
|
this._mesh.geometry.dispose()
|
|
614
|
-
|
|
615
|
+
// material 은 MaterialBank 공유(앱 수명) — 여기서 dispose 하면 다른 인스턴스가 깨진다.
|
|
615
616
|
this._mesh = undefined
|
|
616
617
|
}
|
|
617
618
|
this.build()
|
|
@@ -628,8 +629,8 @@ class OHTLineRealObject3D extends RealObjectGroup {
|
|
|
628
629
|
super.onchange(after, before)
|
|
629
630
|
}
|
|
630
631
|
|
|
632
|
+
// updateAlpha override 제거 — 코어 RealObject.updateAlpha(=applyMaterialOpacity)로 수렴(faint).
|
|
631
633
|
updateDimension() {}
|
|
632
|
-
updateAlpha() {}
|
|
633
634
|
}
|
|
634
635
|
|
|
635
636
|
registerRealObjectFactory('OHTLine', (component: Component) => new OHTLineRealObject3D(component))
|
package/src/factories/oht-3d.ts
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
import * as THREE from 'three'
|
|
13
13
|
import * as BufferGeometryUtils from 'three/examples/jsm/utils/BufferGeometryUtils.js'
|
|
14
14
|
import { RoundedBoxGeometry } from 'three/examples/jsm/geometries/RoundedBoxGeometry.js'
|
|
15
|
-
import { RealObjectGroup, registerRealObjectFactory, disposeObject3D } from '@hatiolab/things-scene'
|
|
15
|
+
import { RealObjectGroup, registerRealObjectFactory, disposeObject3D, MaterialBank } from '@hatiolab/things-scene'
|
|
16
16
|
import type { Component } from '@hatiolab/things-scene'
|
|
17
17
|
import { TRANSPORT_SURFACE_HEIGHT } from './machine-3d.js'
|
|
18
18
|
|
|
@@ -77,11 +77,8 @@ export class OHT3D extends RealObjectGroup {
|
|
|
77
77
|
const armThickness = Math.min(w, h) * 0.12
|
|
78
78
|
const bodyCornerR = Math.min(w, h, bodyH) * 0.1
|
|
79
79
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
roughness: 0.5,
|
|
83
|
-
metalness: 0.4,
|
|
84
|
-
})
|
|
80
|
+
// MaterialBank 공유 — dedup + faint 안전(코어 변형 스왑, disposeObject3D 가 __bankOwned 스킵).
|
|
81
|
+
const frameMat = MaterialBank.material('oht|frame', { roughness: 0.5, metalness: 0.4 }, FRAME_COLOR)
|
|
85
82
|
|
|
86
83
|
// ── 1. 하단 그리퍼 바 (캐리어를 집는 가로 바 — 이동 방향과 직교) ──
|
|
87
84
|
const gripperBarW = w * 0.7
|
|
@@ -116,11 +113,7 @@ export class OHT3D extends RealObjectGroup {
|
|
|
116
113
|
const bodyBaseY = armBaseY + armH
|
|
117
114
|
const bodyColor = this.resolveColor()
|
|
118
115
|
const bodyGeo = new RoundedBoxGeometry(w, bodyH, h, 4, bodyCornerR)
|
|
119
|
-
const bodyMat =
|
|
120
|
-
color: bodyColor,
|
|
121
|
-
roughness: 0.3,
|
|
122
|
-
metalness: 0.5,
|
|
123
|
-
})
|
|
116
|
+
const bodyMat = MaterialBank.material('oht|body', { roughness: 0.3, metalness: 0.5 }, bodyColor)
|
|
124
117
|
const bodyMesh = new THREE.Mesh(bodyGeo, bodyMat)
|
|
125
118
|
bodyMesh.position.y = bodyBaseY + bodyH / 2
|
|
126
119
|
bodyMesh.castShadow = true
|
|
@@ -131,11 +124,7 @@ export class OHT3D extends RealObjectGroup {
|
|
|
131
124
|
const trolleyW = w * 0.6
|
|
132
125
|
const trolleyD = h * 1.15
|
|
133
126
|
const trolleyGeo = new THREE.BoxGeometry(trolleyW, trolleyH, trolleyD)
|
|
134
|
-
const trolleyMat =
|
|
135
|
-
color: TROLLEY_COLOR,
|
|
136
|
-
roughness: 0.6,
|
|
137
|
-
metalness: 0.3,
|
|
138
|
-
})
|
|
127
|
+
const trolleyMat = MaterialBank.material('oht|trolley', { roughness: 0.6, metalness: 0.3 }, TROLLEY_COLOR)
|
|
139
128
|
const trolleyMesh = new THREE.Mesh(trolleyGeo, trolleyMat)
|
|
140
129
|
trolleyMesh.position.y = trolleyBaseY + trolleyH / 2
|
|
141
130
|
trolleyMesh.castShadow = true
|
|
@@ -156,6 +145,9 @@ export class OHT3D extends RealObjectGroup {
|
|
|
156
145
|
|
|
157
146
|
this._ownMeshes = [gripperMesh, armMesh, bodyMesh, trolleyMesh, ...wheelMeshes]
|
|
158
147
|
for (const m of this._ownMeshes) this.components3D.add(m)
|
|
148
|
+
|
|
149
|
+
// mesh 는 super.build() 이후 생성 → 코어 faint 를 명시 적용(편집 흐림이 mesh 에 닿게).
|
|
150
|
+
this.updateAlpha()
|
|
159
151
|
}
|
|
160
152
|
|
|
161
153
|
updateDimension() {}
|
|
@@ -172,16 +164,8 @@ export class OHT3D extends RealObjectGroup {
|
|
|
172
164
|
this.updateHidden()
|
|
173
165
|
}
|
|
174
166
|
|
|
175
|
-
updateAlpha()
|
|
176
|
-
|
|
177
|
-
for (const m of this._ownMeshes) {
|
|
178
|
-
const materials = Array.isArray(m.material) ? m.material : [m.material]
|
|
179
|
-
for (const mat of materials) {
|
|
180
|
-
;(mat as THREE.MeshStandardMaterial).opacity = alpha
|
|
181
|
-
;(mat as THREE.MeshStandardMaterial).transparent = alpha < 1
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
}
|
|
167
|
+
// updateAlpha override 제거 — 코어 RealObject.updateAlpha(=applyMaterialOpacity)로 수렴.
|
|
168
|
+
// canonical(bank base opacity 1) × state.alpha × faint. view 모드 불변, 편집 모드 faint 추가.
|
|
185
169
|
|
|
186
170
|
onchange(after: Record<string, unknown>, before: Record<string, unknown>) {
|
|
187
171
|
if ('width' in after || 'height' in after || 'depth' in after ||
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
import * as THREE from 'three'
|
|
14
14
|
import * as BufferGeometryUtils from 'three/examples/jsm/utils/BufferGeometryUtils.js'
|
|
15
|
-
import { RealObjectGroup, registerRealObjectFactory, disposeObject3D } from '@hatiolab/things-scene'
|
|
15
|
+
import { RealObjectGroup, registerRealObjectFactory, disposeObject3D, MaterialBank } from '@hatiolab/things-scene'
|
|
16
16
|
import type { Component } from '@hatiolab/things-scene'
|
|
17
17
|
import { TRANSPORT_SURFACE_HEIGHT } from './machine-3d.js'
|
|
18
18
|
|
|
@@ -68,11 +68,9 @@ export class Shuttle3D extends RealObjectGroup {
|
|
|
68
68
|
// ── 1. 하단 베이스 플레이트 (납작하고 넓은 주행부) ──
|
|
69
69
|
const basePad = Math.min(w, h) * 0.05
|
|
70
70
|
const baseGeo = new THREE.BoxGeometry(w + basePad * 2, baseH, h + basePad * 2)
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
metalness: 0.3,
|
|
75
|
-
})
|
|
71
|
+
// MaterialBank 공유 — 정적/상태색 dedup + faint 안전(코어가 공유 base 변형 스왑). dispose 는
|
|
72
|
+
// disposeObject3D 가 __bankOwned 를 건너뛰어 안전.
|
|
73
|
+
const baseMat = MaterialBank.material('shuttle|base', { roughness: 0.7, metalness: 0.3 }, BASE_COLOR)
|
|
76
74
|
const baseMesh = new THREE.Mesh(baseGeo, baseMat)
|
|
77
75
|
baseMesh.position.y = baseH / 2
|
|
78
76
|
baseMesh.castShadow = true
|
|
@@ -81,11 +79,7 @@ export class Shuttle3D extends RealObjectGroup {
|
|
|
81
79
|
// ── 2. 좌우 마스트 기둥 (statusColor 적용) ──
|
|
82
80
|
const mastBaseY = baseH
|
|
83
81
|
const bodyColor = this.resolveColor()
|
|
84
|
-
const mastMat =
|
|
85
|
-
color: bodyColor,
|
|
86
|
-
roughness: 0.4,
|
|
87
|
-
metalness: 0.5,
|
|
88
|
-
})
|
|
82
|
+
const mastMat = MaterialBank.material('shuttle|mast', { roughness: 0.4, metalness: 0.5 }, bodyColor)
|
|
89
83
|
|
|
90
84
|
const mastGeometries: THREE.BufferGeometry[] = []
|
|
91
85
|
|
|
@@ -108,11 +102,7 @@ export class Shuttle3D extends RealObjectGroup {
|
|
|
108
102
|
|
|
109
103
|
// ── 3. 상단 포크 (2개의 평행 암 + 백 플레이트) ──
|
|
110
104
|
const forkBaseY = mastBaseY + mastH
|
|
111
|
-
const forkMat =
|
|
112
|
-
color: FORK_COLOR,
|
|
113
|
-
roughness: 0.4,
|
|
114
|
-
metalness: 0.6,
|
|
115
|
-
})
|
|
105
|
+
const forkMat = MaterialBank.material('shuttle|fork', { roughness: 0.4, metalness: 0.6 }, FORK_COLOR)
|
|
116
106
|
|
|
117
107
|
const forkGeometries: THREE.BufferGeometry[] = []
|
|
118
108
|
|
|
@@ -139,6 +129,9 @@ export class Shuttle3D extends RealObjectGroup {
|
|
|
139
129
|
|
|
140
130
|
this._ownMeshes = [baseMesh, mastMesh, forkMesh]
|
|
141
131
|
for (const m of this._ownMeshes) this.components3D.add(m)
|
|
132
|
+
|
|
133
|
+
// mesh 는 super.build() 이후 생성 → 코어 faint 를 명시 적용(편집 흐림이 mesh 에 닿게).
|
|
134
|
+
this.updateAlpha()
|
|
142
135
|
}
|
|
143
136
|
|
|
144
137
|
updateDimension() {}
|
|
@@ -155,16 +148,9 @@ export class Shuttle3D extends RealObjectGroup {
|
|
|
155
148
|
this.updateHidden()
|
|
156
149
|
}
|
|
157
150
|
|
|
158
|
-
updateAlpha()
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
const materials = Array.isArray(m.material) ? m.material : [m.material]
|
|
162
|
-
for (const mat of materials) {
|
|
163
|
-
;(mat as THREE.MeshStandardMaterial).opacity = alpha
|
|
164
|
-
;(mat as THREE.MeshStandardMaterial).transparent = alpha < 1
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
}
|
|
151
|
+
// updateAlpha override 제거 — 코어 RealObject.updateAlpha(=applyMaterialOpacity)로 수렴.
|
|
152
|
+
// 코어가 canonical(=bank base, opacity 1) 위에 state.alpha × faint 를 일괄. view 모드는
|
|
153
|
+
// 1×state.alpha = 기존 in-place 결과와 동일 → 불변, 편집 모드만 faint 추가.
|
|
168
154
|
|
|
169
155
|
onchange(after: Record<string, unknown>, before: Record<string, unknown>) {
|
|
170
156
|
if ('width' in after || 'height' in after || 'depth' in after ||
|
package/src/mcs-machine.ts
CHANGED
|
@@ -84,32 +84,13 @@ export default class MCSMachine extends MCSStatusMixin(ContainerAbstract) {
|
|
|
84
84
|
}
|
|
85
85
|
|
|
86
86
|
/**
|
|
87
|
-
*
|
|
88
|
-
*
|
|
89
|
-
*
|
|
90
|
-
* const fade = (alpha || 1) - this._delta.fade
|
|
91
|
-
* if (fade) context.globalAlpha = fade
|
|
92
|
-
*
|
|
93
|
-
* It *overwrites* `globalAlpha` (not multiplies), so the inherited
|
|
94
|
-
* parent alpha is also lost — that's a base-layer quirk we match the
|
|
95
|
-
* recovery for. Then at line 48 it applies editMode+hidden dimming
|
|
96
|
-
* with a *= 0.5.
|
|
97
|
-
*
|
|
98
|
-
* Our recovery:
|
|
99
|
-
* 1. Capture the inherited `globalAlpha` *before* super runs.
|
|
100
|
-
* 2. Let super do its work (transforms / shadow / dim flags).
|
|
101
|
-
* 3. Restore globalAlpha to inherited × editMode-hidden dim factor —
|
|
102
|
-
* i.e., what super would have produced if our state.alpha were 1.
|
|
103
|
-
*
|
|
104
|
-
* 3D path is unaffected: 3D factories read `state.alpha` directly via
|
|
105
|
-
* their `updateAlpha()` implementations and continue to honor it (with
|
|
106
|
-
* per-config opacity fallback).
|
|
87
|
+
* 2D 에서는 `state.alpha`(3D material 전용)를 무시한다. hidden/모델링 dim 흐림은 **코어(draw)가
|
|
88
|
+
* 일괄 처리**하므로 여기서 손대지 않는다 (component-drawing.ts draw 가 prerender 직후 faint 적용).
|
|
89
|
+
* fade 애니메이션은 보존. 3D 는 factory `updateAlpha()` 가 state.alpha 를 별도로 존중.
|
|
107
90
|
*/
|
|
108
91
|
prerender(ctx: any) {
|
|
109
|
-
const inherited = ctx.globalAlpha
|
|
110
92
|
super.prerender(ctx)
|
|
111
|
-
|
|
112
|
-
ctx.globalAlpha = inherited * dim
|
|
93
|
+
ctx.globalAlpha = 1 - this._delta.fade
|
|
113
94
|
}
|
|
114
95
|
|
|
115
96
|
render(ctx) {
|
package/src/mcs-unit.ts
CHANGED
|
@@ -62,14 +62,11 @@ export default class MCSUnit extends MCSStatusMixin(ParentObjectMixin(ContainerA
|
|
|
62
62
|
}
|
|
63
63
|
|
|
64
64
|
/**
|
|
65
|
-
*
|
|
66
|
-
* See MCSMachine.prerender for the full rationale.
|
|
65
|
+
* 2D 에서는 state.alpha 무시. hidden/모델링 dim 흐림은 코어(draw)가 일괄 처리 (MCSMachine 동일).
|
|
67
66
|
*/
|
|
68
67
|
prerender(ctx: any) {
|
|
69
|
-
const inherited = ctx.globalAlpha
|
|
70
68
|
super.prerender(ctx)
|
|
71
|
-
|
|
72
|
-
ctx.globalAlpha = inherited * dim
|
|
69
|
+
ctx.globalAlpha = 1 - this._delta.fade
|
|
73
70
|
}
|
|
74
71
|
|
|
75
72
|
contains(x, y) {
|
|
@@ -217,6 +217,7 @@ Object.defineProperty(ModelLayer.prototype, 'nature', {
|
|
|
217
217
|
type: 'legend',
|
|
218
218
|
label: '',
|
|
219
219
|
name: 'MOOD',
|
|
220
|
+
requires3d: true,
|
|
220
221
|
property: {
|
|
221
222
|
label: 'MOOD'
|
|
222
223
|
}
|
|
@@ -225,6 +226,7 @@ Object.defineProperty(ModelLayer.prototype, 'nature', {
|
|
|
225
226
|
type: 'select',
|
|
226
227
|
label: 'light-preset',
|
|
227
228
|
name: 'lightPreset',
|
|
229
|
+
requires3d: true,
|
|
228
230
|
property: {
|
|
229
231
|
options: ['dark', 'medium', 'bright']
|
|
230
232
|
}
|